-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 0193fbc
Showing
50 changed files
with
687 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. | ||
|
||
[](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](<attack-vectors/Frontend_(Off_Chain)_Attacks.md>) | ||
- [Short Address Attack](<attack-vectors/Frontend_(Off_Chain)_Attacks.md/>) | ||
- [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)](<attack-vectors/Right-To-Left-Override_control_character_(U%2B202E).md>) | ||
- [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) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,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. |
5 changes: 5 additions & 0 deletions
5
attack-vectors/Account_Existence_Check_for_low_level_calls.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,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/) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,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/#) |
Oops, something went wrong.