Skip to content

Commit

Permalink
send and init
Browse files Browse the repository at this point in the history
  • Loading branch information
behrouzT committed Mar 28, 2023
0 parents commit 0193fbc
Show file tree
Hide file tree
Showing 50 changed files with 687 additions and 0 deletions.
80 changes: 80 additions & 0 deletions README.md
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.

[![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](<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)

49 changes: 49 additions & 0 deletions attack-vectors/Access_Control.md
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 attack-vectors/Account_Existence_Check_for_low_level_calls.md
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.
5 changes: 5 additions & 0 deletions attack-vectors/Arbitrary_Jumps_with_Function_Variables.md
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)
5 changes: 5 additions & 0 deletions attack-vectors/Assert_Violation.md
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)
3 changes: 3 additions & 0 deletions attack-vectors/Bypass_Contract_Size_Check.md
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/)
3 changes: 3 additions & 0 deletions attack-vectors/Code_With_No_Effects.md
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.
3 changes: 3 additions & 0 deletions attack-vectors/Complex_Modifiers.md
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)
27 changes: 27 additions & 0 deletions attack-vectors/DOS.md
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)
3 changes: 3 additions & 0 deletions attack-vectors/Dirty_Higher_Order_Bits.md
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)
5 changes: 5 additions & 0 deletions attack-vectors/Entropy_Illusion.md
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)
1 change: 1 addition & 0 deletions attack-vectors/Experimental_Language_Features.md
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.
3 changes: 3 additions & 0 deletions attack-vectors/External_Contrac_Referencing.md
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)
1 change: 1 addition & 0 deletions attack-vectors/Flash_Loan_Attack.md
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.
3 changes: 3 additions & 0 deletions attack-vectors/Floating_Point_Arithmetic.md
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)
82 changes: 82 additions & 0 deletions attack-vectors/Force_Feeding.md
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/#)
Loading

0 comments on commit 0193fbc

Please sign in to comment.