Nathan Ostrowski Profile picture
Jul 25 20 tweets 5 min read Twitter logo Read on Twitter
Why @zksync @Era_Lend was just attacked for $3.4M, and how to prevent it happening elsewhere. A comprehensive thread 🧵 Image
Today’s $3.4M attack follows a relatively new pattern of read-only reentrancy and oracle manipulation.


It’s not the first to face this issue, and it won’t be the last. Let’s break this down:explorer.zksync.io/tx/0x99efebacb…
Reentrancy is something most people who deal with smart contracts have probably heard before. It’s when an attacker can enter a function once, then ‘re-enter’ that function again before the original function is finished.
This is often due to some external call in the middle of the function.

The flow is typically: Action A -> External Call -> Action B.

When unprotected, the attacker can leverage the External Call to take Action A many times before Action B. Image
Many examples here: github.com/pcaversaccio/r…
Typically contract devs protect from this by writing “reentrancy locks”––in other words, making sure that function calls are made one-at-a-time. Image
Locks often prevent attackers from re-entering the same function (Single Function Reentrancy).

But when state is used across contracts, attackers can use an outdated value to take malicious action in another contract (Cross-contract Reentrancy). This is how @Era_Lend lost $3.4M. https://inspexco.medium.com/cross-contract-reentrancy-attack-402d27a02a15
We say reentrancy is “read-only” when the function it calls is a “view” function that can’t change the underlying state.

Because it can’t change state, many devs see it as benign––and leave these functions unguarded.
However, attackers can leverage these seemingly benign functions to create inconsistent values across contracts.

In zkSync’s EraLend, the attacker created an inconsistent value across the SyncSwap liquidity pool and the EraLend contracts. Image
The intended movement of this SyncSwap function should be:
1. Burn the pool’s liquidity tokens, return the assets
2. Optional callback to read information
3. Update the reserve info
However, because EraLend was calculating prices from the reserve info, and reserve info was updated at the end, the attacker was able to exploit this callback in the middle and have EraLend fetch stale information.
The malicious flow is:
1. Attacker burns liquidity tokens, returns assets, reserve info becomes outdated
2. Callback, execution flow switches to new contract (EraLend)
3. EraLend contract grabs the reserve info of the SyncSwap pool––remember it’s outdated...
4. EraLend contract sees outdated reserve info, uses it to calculate price
5. Attacker uses the inaccurate price to steal from the EraLend contract. The SyncSwap contract only updates the reserve info after it’s too late.

How do we fix this? Image
Outdated information is the key problem. The attacker was able to transfer control to the callback contract (EraLend) with an outdated value.
SyncSwap could have changed its flow (avoiding a callback with outdated info), or EraLend could have changed their query to reflect the fact that the tokens and reserves could be out-of-sync.

Either way, EraLend could have avoided an attack.
Identifying cross-contract behavior can be tough. It's never enough to just analyze your own contracts if you're interacting with others.
Finally, I want to give credit where it’s due.

@_iphelix pointed out during the @summit_defi that far more people have been focused on helping auditors better attack smart contracts, and not nearly enough time has been spent helping developers write secure contracts easily.
By funneling resources into auditing, we’ve been feeding the expensive consultant model, while not addressing the root security problem. This is one of the biggest barriers to making blockchain tech mainstream.
If you also feel this problem: that developers should be empowered to write secure code themselves without needing to be security experts, come talk to us about the brand-new solution we’re building at @octane_security

• • •

Missing some Tweet in this thread? You can try to force a refresh
 

Keep Current with Nathan Ostrowski

Nathan Ostrowski Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

PDF

Twitter may remove this content at anytime! Save it as PDF for later use!

Try unrolling a thread yourself!

how to unroll video
  1. Follow @ThreadReaderApp to mention us!

  2. From a Twitter thread mention us with a keyword "unroll"
@threadreaderapp unroll

Practice here first or read more on our help page!

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just two indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3/month or $30/year) and get exclusive features!

Become Premium

Don't want to be a Premium member but still want to support us?

Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal

Or Donate anonymously using crypto!

Ethereum

0xfe58350B80634f60Fa6Dc149a72b4DFbc17D341E copy

Bitcoin

3ATGMxNzCUFzxpMCHL5sWSt4DVtS8UqXpi copy

Thank you for your support!

Follow Us on Twitter!

:(