Smart contract security analysis, targeting ERC777 arbitrary call contract Hook attack

Smart contract security analysis, targeting ERC777 arbitrary call contract Hook attack

Safful discovered an interesting bug that could become an attack vector for some DeFi projects. This error is especially related to the well-known ERC777 token standard. Furthermore, it is not just a simple re-entrancy problem commonly seen in well-known hackers.

This article provides a comprehensive explanation of ERC777, covering all the necessary details. There are few resources that delve into the specific details of ERC777 tokens, and this article is a valuable detailed guide for anyone interested in learning more about ERC777 tokens.
In the final part of the article, our recent findings will be explained.

Brief description of the attack vector

This vulnerability takes advantage of the characteristics of ERC777 and can set up a Hook receiving function. By leveraging the ability to make arbitrary calls within the target contract, a malicious caller can call the ERC777 registry contract and assign a specific Hook address to the target contract. Therefore, as long as the target contract receives ERC777 tokens in the future, the attacker's Hook contract will be triggered. This hook can be exploited in various ways: either for a reentrancy attack to steal tokens, or simply to roll back the transaction, preventing the target contract from sending or receiving ERC777 tokens.

ERC777 and its Hook

What is ERC777

ERC777 is one of the token standards with transfer hooks.
Here is the EIP description: https://eips.ethereum.org/EIPS/eip-777 , and here is an ERC777 practice .
The main motivation for implementing ERC777 tokens is to imitate the behavior of native token transfers. By triggering smart contracts when tokens are received, developers can execute specific logic to enhance functionality and create more dynamic token interactions.
However, these extra calls during the transfer process make ERC777 different from ERC20 tokens. These hooks introduce a new attack vector that may affect smart contracts that are not designed to handle additional calls during the token transfer process. This unexpected behavior creates security risks for these contracts.
The following is a list of some ERC777 tokens with some liquidity on the Ethereum mainnet:
VRA: https://etherscan.io/address/0xf411903cbc70a74d22900a5de66a2dda66507255
AMP: https://etherscan.io/address/0xff20817765cb7f73d4bde2e66e067e5
8d11095c2 LUKSO: https://etherscan .io/address/0xa8b919680258d369114910511cc87595aec0be6d
SKL: https://etherscan.io/address/0x00c83aecc790e8a4453e5dd3b0b4b3680501a7a7
imBTC:https://etherscan.io/address/0x3212b29e33587a00fb1c83346f5dbfa69a458923
CWEB:https://etherscan.io/address/0x505b5eda5e25a67e1c24a2bf1a527ed9eb88bf04
FLUX:https://etherscan.io/address/0x469eda64aed3a3ad6f868c44564291aa415cb1d9

When Hook occurs

ERC20 tokens simply update the balance during the transfer process. But ERC777 tokens do this:

  1. Make a Hook call to the token originator's address
  2. Update balance
  3. Make a Hook call to the token receiver address

This is well illustrated in the VRA token:

Source code: https://etherscan.io/address/0xf411903cbc70a74d22900a5de66a2dda66507255
Now, let’s check the code for these calls:

As you can see:

  1. This function reads the contract called implementer from _ERC1820_REGISTRY
  2. If the function finds an implementer, that implementer will be called.

Let's study this registry and see what an implementer is.

Registry and implementers

All ERC777 tokens are related to the contract of the Registry: https://etherscan.io/address/0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24.
This address is used by the ERC777 token to store the set Hook recipient. These Hook receivers are called "interface implementers".
This means that Alice can choose Bob as her interface implementer. If Alice receives or sends ERC777 tokens, Bob will receive the Hook.
Alice can manage different Hook types. Therefore, when Alice sends tokens, she can choose Bob as the interface implementer, and only when Alice receives the tokens, she chooses Tom as the implementer.
In most cases, she can also choose different interface implementers for different tokens.
These preferences are stored in this map's registry:

_interfaceHash is the identifier of the interface implementer Alice chooses for an event.
And anyone can use this function to read Alice's interface implementer:

As you can see, this is the function we encountered earlier in the VRA code.
The variable _TOKENS_SENDER_INTERFACE_HASH is used as _interfaceHash, it can be any byte. But the VRA token uses these bytes to identify this type of Hook:

Receive Hook

To set up a Hook receiving function, Alice simply calls this function on the registry and enters Bob's address as the _implementer parameter.

She must also specify an _interfaceHash. She will get this _TOKENS_SENDER_INTERFACE_HASH from the VRA token code.
There is one more important detail.
After setting up the implementer for the VRA above, Alice will also realize that Bob will receive the call even if other ERC777 tokens are transferred.
For example , imBTC has the same _interfaceHash on the sent token.
This is due to the fact that all ERC777 tokens share the same registry contract to store Hook preferences. But it's up to the ERC777 tokens to assign names to their Hooks, and while sometimes they are similar, that's not always the case.

How to find ERC777 tokens

Calling the registry is a feature shared by all ERC777.
Therefore, we can try dune.com to call all smart contracts that call the registry.

We can use this SQL script. In fact, we should have additionally filtered out token addresses, but at least we had a perfect start and ended up with 78 addresses.
Translator's Note: The dune traces table will record internal transaction call records.

Is this registry the only one possible?

Theoretically, no one can guarantee that some tokens happen to use this 0x1820 contract as a registry.
But we can use dune.com to check.

it returns these addresses

0x1820a4b7618bde71dce8cdc73aab6c95905fad24
0xc0ce3461c92d95b4e1d3abeb5c9d378b1e418030
0x820c4597fc3e4193282576750ea4fcfe34ddf0a7

We checked and 0x1820 is the only registry that has valuable ERC777 tokens. The tokens of other registries are not as valuable.

The Common Case for Hookable Tokens

ERC777 is not just a standard with Hooks. Also ERC223, ERC995 or ERC667.
They are not that unusual. You must have heard of the LINK token that implements ERC667 .

Attack vectors using arbitrary calls

This is a recently discovered attack vector for Safful 's customers.
Researchers generally believe that ERC777 tokens make calls to call originators and receivers. But in fact, the initiator and receiver can choose any "Bob" as the Hook receiver.
So imagine what would happen if you combined those contracts with any data to make arbitrary calls to any address?
The arbitrary calling function can be widely used in DEX aggregators, wallets, and multicall contracts.
Translator's Note: Arbitrary call function refers to the existence of a function similar to this in the contract:
function execute(address target, uint value, string memory signature, bytes memory data, uint eta) public payable;
it can call any other method.
Attack method:

  1. The attacker finds a target contract (Target) that allows arbitrary calling of functions
  2. The attacker calls on the target:
  3. registy1820.setInterfaceImplementer(Target, hookHash, Attacker)
  4. Now, our Attacker is the implementer of Target
  5. Attacker will be called with the hookHash used in ERC777 tokens.
  6. Whenever the target contract (Target) receives ERC777 tokens, the Attacker will receive a Hook call.
  7. The following attacks vary depending on the Target code:
    • Attacker can perform reentrancy when some users execute functions in the target contract
    • Attacker can roll back directly, so that the user's transaction is directly restored.

If the DEX aggregator calculates that the best exchange path is through a certain DEX trading pair with ERC777 tokens, then it may encounter problems.

Protect

After hours of discussion with the customer, we found a solution that wouldn't break arbitrary calls.
It is best for the project side to limit the use of Registry1820 as the address for any calls. Therefore, no attacker can exploit arbitrary calls to set the interface implementer.

Experience

Projects and auditors must be aware of the Hook behavior described in ERC777. These tokens not only make calls to the receiver and initiator, but also to some other Hook receivers.
In this sense, projects that allow arbitrary calls must pay special attention and consider ERC777 as another attack vector.

Guess you like

Origin blog.csdn.net/weixin_28733483/article/details/132654448