One of the BlockSec DeFi attack analysis series I speak for myself: ChainSwap attack event analysis

BlockSec
本文约5354字,阅读全文需要约21分钟
BlockSec, as a research team that has long been concerned about DeFi security, has independently discovered a number of DeFi security incidents. Today it released the first article in this series, the ChainSwap attack incident of the decentralized cross-

Decentralized finance (DeFi), as a popular project form in the blockchain ecology, its security is particularly important. Since last year, dozens of security incidents have occurred. As a long-term research team (https://blocksecteam.com) concerned with DeFi security, BlockSec has independently discovered a number of DeFi security incidents, and the research results have been published in top security conferences (including USENIX Security, CCS and Blackhat). In the next period of time, we will systematically analyze DeFi security incidents and analyze the root causes behind the security incidents.

0xffffffff. Preface

0xffffffff. Preface

In the early morning of July 11, 2021, Beijing time, ChainSwap, a decentralized cross-chain asset bridge project, was attacked again. 20+ projects deployed on the cross-chain bridge were attacked, and the loss exceeded 8 million US dollars. This is the history of DeFi development. The worst attack to date. This article will analyze all the details of the attack.

If you are new to DeFi, you can read it from the beginning, but the article is long, remember to pay attention before you go

Reading suggestions:

  • If you are new to DeFi, you can read it from the beginning, but the article is long, remember to pay attention before you go

  • 0x0. Background introduction

0x0. Background introduction

ChainSwap is a Cross-Chain Asset Bridge. The so-called cross-chain asset bridge is essentially to solve the problem of asset transfer in multiple smart contract chains. For example, if USDT tokens on the Binance Smart Chain (BSC) chain want to be converted to the Ethereum main chain for transactions, they must be converted through a cross-chain asset bridge. ChainSwap, Ren Protocol, etc. are currently representative cross-chain asset bridge projects, which carried tens of millions of dollars in cross-chain transactions, which also caused extremely heavy losses caused by this attack.

① Cross-chain asset bridge ChainSwap

With the continuous development of Ethereum and the decentralized finance (DeFi) ecosystem based on Ethereum, more and more smart contract blockchains based on the Ethereum Virtual Machine have emerged, including the Binance Smart Chain (Binance Smart Chain, BSC), Huobi Eco Chain (HECO) and TRON Chain.

In the scenario where multiple smart contract chains coexist, due to the need for token exchange on different chains, the cross-chain asset bridge project has gradually entered people's field of vision. Traditional cross-chain asset bridges such as Shapeshift and ChangeNOW are centralized services. In the context of decentralization, decentralized cross-chain asset bridge projects continue to emerge, and ChainSwap is one of the representative services.

The biggest difficulty in designing a cross-chain asset bridge is how to verify transactions between different chains. In response to this problem, ChainSwap adopted a PoA (Proof of Authority) mechanism.

There is a group of validator nodes (this node can be a person or a contract) in the entire ChainSwap network. The job of these nodes is to verify transactions on one chain and provide proofs on another chain. For example, suppose user A wants to transfer 1000USDT on the Ethereum chain to the BSC chain, the transfer operation is as follows:

  • First, on the Ethereum chain, the service calls the send method of the contract on the chain, sends the user's 1000USDT to the ChainSwap contract on the Ethereum, and generates a sending transaction.

  • Subsequently, ChainSwap will send the transaction information to a set of verifiers, who will verify the transaction and return a set of signatures.

  • Finally, on the BSC chain, the service calls the receive method of the contract on the chain, and receives 1000USDT on the BSC chain and sends it back to the user. This call sends the signature of the transaction on Ethereum to verify the transaction on the Ethereum chain.

② Overview of the implementation mechanism of ChainSwap

Essentially, ChainSwap is a matchmaker for transactions on different chains. Taking the above transfer operation as an example, the second step requires an independent verifier to prove the transfer operation of the user on the Ethereum chain. So how to implement an efficient and secure signature mechanism?

Let's go back to the basics of Ethereum. The process of generating an address for an Ethereum user is as follows: First, a huge random number is generated as a private key (Private Key), and the private key can obtain a public key (Public Key) through a certain single-item algorithm, and then through a one-way hash algorithm Generate address. So in essence, behind the address corresponds to the private key.

The private key can be used not only for decryption, but also for signing. Specifically, anyone (in this case, a ChainSwap validator) can serialize a message and generate a corresponding signature with a private key. The signature consists of four parts: the digest of the message (Digest) and three parameters (R, V, S).

After signing, how to verify the validity of the signature? The Solidity programming language of the smart contract provides the ecrecover function, which can calculate the address of signing the message through the above four parameters. The implementer of the contract must verify whether this address is valid by itself. We will see later that it was the failure to verify the validity of the address that led to the attack on ChainSwap. ③ Overview of the implementation mechanism of ChainSwap Before analyzing the code and attack, first outline the implementation mechanism of ChainSwap:

  • As a cross-chain asset bridge, ChainSwap sets up a Factory (factory model) to manage and query subordinate projects, that is, to find the address of the cross-chain currency on the Ethereum main chain.

  • Each project can apply to ChainSwap for docking and automatically become a cross-chain token. ChainSwap will create a mapping Token (TokenMapped) for these tokens to represent the "mapping" of the Token on the chain.

  • 0x1. Code Analysis

0x1. Code Analysis

ChainSwap will create a TokenMapped contract for each token undertaken by the project to represent the mapping of the token on the chain. The attacker's entry point is the receive method of the TokenMapped contract. Let's analyze the relevant code step by step to see how the attack is implemented.

① Attack entry analysis

The figure above shows the entire code of the receive function. Under normal circumstances, after the user sends some kind of Token to ChainSwap on other chains, the transaction is verified by the signer, and the user can send the verification information to the ChainSwap contract on the Ethereum main chain, which will transfer the Token to the user after verification . receive implements exactly such a process.

The implementation of this function is relatively complicated, and a fee of 0.05ETH is charged at the beginning (through the _chargeFee internal function). Next, the contract requests parameters from ChainSwap Factory, obtains the minimum number of signatures (parameter minSignatures), and verifies the number of incoming signatures. It can be found from the transaction records that this value is 1, which means that cross-chain transactions only need the signature of one signatory to pass. The modification process of this parameter will be described later.

Then for each signature, first routinely verify whether the incoming signature array is duplicated. Second, verify the validity of the signature through ecrecover. This step is a conventional signature verification process, and since it has nothing to do with the attack itself, it will not be described in detail. Finally, reduce the authenticator's quota via _decreaseAuthQuota. Seeing this, the entire implementation logic seems complete and clear.

However, through the above analysis process, we found that the entry function receive does not verify the identity of the signatory (Signatory), and the existence of the Signatory parameter is only used to cooperate with the ecrecover function to verify whether the message is indeed signed by the Signatory. That is, anyone can generate a signature. Maybe Signatory is validated in an inner function called by the receive function? Let's continue reading.

The figure above shows the implementation of the first internal function _decreaseAuthQuota. The main function of this function is to reduce the quota value corresponding to Signatory recorded in the _authQuotas mapping. The implementation itself is very simple, but the modifier part shown in the red line caught our attention. _decreaseAuthQuota does not check the validity of Signatory, so is this modifier verified?

The figure above shows the implementation of updateAutoQuota(signatory). Modifier is a syntactic sugar of the Solidity language. Take the modifier shown in the above figure as an example. The function modified by this modifier will add itself to the function. The dash in the last line indicates that the real function body of the function marked by the modifier will appear Location. It can be seen that the implementation of the modifier is to call the authQuotaOf function to update the Signatory quota first, and update it according to the conditions. Notice that the validity of Signatory is not verified after calling authQuotaOf.

Finally, let's look at the implementation of authQuotaOf. First, directly obtain the quota of Signatory in the _authQuotas mapping. Unlike mainstream programming languages ​​such as Python, Solidity has no concept similar to KeyError in Python. If the key does not exist in the mapping (mapping), it will return 0, but there is no check for the return value here. Next, calculate the new maximum quota quotaCap through the two parameters of autoQuotaRatio and autoQuotaPeriod. By searching the Ethereum transaction records, the values ​​of these two parameters are 1e15 (0.1% after dividing by 1e18) and 86400 (the number of seconds in a day).

Therefore, the quotaCap calculated in the penultimate line is a very large value (the actual implementation of cap() is IERC20(token).totalSupply(), which is the total supply of tokens on this chain). Therefore, the theoretical maximum value of quotaCap is 0.1% of the token supply.

In the penultimate line, because the Signatory cannot be found in lasttimeUpdateQuotaOf, it returns 0 (the second mistake), so delta can be larger than quotaCap when the Signatory is illegal. The last line calculates and returns the updated quota. Through the above analysis, it is not difficult to see that it is quotaCap that is returned in the attack.

To sum up, the entire implementation process of the receive function does not check the validity of the incoming Signatory. Therefore, the attacker only needs to randomly generate an address and generate the corresponding signature to deceive ChainSwap and provide a signature for himself. At the same time, due to a logical error in the implementation of authQuotaOf, a very large value will be returned when the Signatory is invalid, leading to the occurrence of this attack. The essence of this attack is that the value of the mapping index was not verified. Since Solidity doesn't trigger any errors if the mapped key doesn't exist (it can only be determined by returning a value of 0), this kind of check is very important. It was the (absurd) lack of such a check that cost this attack more than $8 million.

③ Extra chapter 1: Modification of parameter minSignatures

Through the above analysis, it is not difficult to see that the main reason for the attack is the lack of checking of the return value of the mapping index. But the value of the parameter parameter minSignatures also caught our attention. we found in the transaction0x50d462f4, the value of the parameter minSignatures is changed to 1:

This transaction appeared in block 12377182, which is 65 days before the attack. This kind of modification of the underlying parameters of the protocol can only be done by the official (not modified by the attacker himself), and this is also verified by reading the code:

The Factory contract inherits the Configurable contract to provide parameter configuration functions. The governance modifier in the function declaration in the figure means that the function can only be modified by the administrator. We do not know why ChainSwap officially modified this parameter, but this modification increases the unreliability of the system on the one hand, and on the other hand provides convenience for the attacker, because the attacker only needs to construct a signature to deceive the ChainSwap system, Withdraw tokens directly.

④ Extra Story 2: False Verification

Interestingly, in the contract implementation of the manager Factory, ChainSwap designed a variable to save the array composed of Signatory, the code is shown in the following figure:

0x2. Attack Analysis

0x2. Attack Analysis

After the above code analysis, it is not difficult to come up with the simplest attack process: you only need to create multiple addresses in batches, generate and submit signatures. Since TokenMapped does not perform any verification, the tokens locked in the contract can be obtained directly to realize empty hands.
This is how the attacker's real attack is implemented. Taking one of the attack transactions as an example, the transaction execution trace is as follows:

It can be seen that the attack simply calls the buggy receive function shown above, passes in a fake signature, and gets tokens that the attacker should not have obtained.
Scan the QR code to pay attention to more exciting

Driven by core security technology, the BlockSec team has long been concerned with DeFi security, digital currency anti-money laundering and digital asset custody based on privacy computing, providing contract security and digital asset security services for DApp project parties. The team has published more than 20 top security academic papers (CCS, USENIX Security, S&P), and its partners have won the title of AMiner's most influential security and privacy scholar in the world (ranked sixth in the world in 2011-2020). The research results have been awarded by CCTV, Xinhua News agency and overseas media reports. Independently discovered dozens of DeFi security vulnerabilities and threats, and won the first place in the world in the 2019 National Institutes of Health Privacy Computing Competition (SGX Track). Driven by technology, the team adheres to the concept of openness and win-win, and works with community partners to build a safe DeFi ecosystem.
Scan the QR code to pay attention to more exciting

https://www.blocksecteam.com/

contact@blocksecteam.com