Introduction
- Reentrancy is a smart contract vulnerability that allows the attacker the ability to invoke the vulnerable contract in an unexpected state. As you'll see in
Process Diagram,
Attacker
Contract will unexpectedly call (or "re-enter") theVulnerable
Contract before theVulnerable
Contract has updated its state. - In this lesson, you'll learn the theory behind Reentrancy attacks. After you've learned the theory, you'll create your own
Attacker
Contract and exploit this vulnerability within the lab environment! - Do you already have a grasp on how Reentrancy works? Feel free to move to the Reentrancy Fundamentals: Attack Lab and put your knowledge to the test!Tip
Prerequisites
- Basic Solidity knowledge
Code
- The code in this section is vulnerable to a Reentrancy attack. In the
Reentrancy Fundamentals: Attack Lab, you'll create an
Attacker
Contract that exploits this bug.
Tip:
Don't worry if the code (below) doesn't make complete sense. You'll dive into the details within the Process Diagram.
Explanation
- Marker
1
: Before exploiting the Reentrancy vulnerability, theAttacker
Contract must complete some prerequisite work. In this case,deposit()
is called to give the attacker a positive balance. (The reasoning for this step will be evident soon.) - Marker
2
: TheAttacker
Contract callswithdrawAll()
to start the main portion of the attack. - Marker
3
: This condition passes due to Marker1
. -
Marker
4
msg.sender
refers to the address that calledwithdrawAll()
. For the purposes of this example, we'll refer to this asattacker_address
.- When
attacker_address
initially callswithdrawAll()
,beginExecutionBalance
is equal to the amount ofETH
thatattacker_address
initially deposited into the contract. call()
is a low-level Solidity function that can sendETH
to another address. When thiscall()
occurs, the execution flow is delegated to theAttacker
Contract which allows theAttacker
Contract to callwithdrawAll()
again. This secondwithdrawAll()
occurs before the state update (Marker5
) occurs. As theVulnerable
Contract can be "re-entered" before it updates its state,Vulnerable
Contract is vulnerable to a Reentrancy attack. When theAttacker
Contract callswithdrawAll()
for the second time, Marker3
will evaluate tofalse
asbeginExecutionBalance
hasn't (yet) been set to0
. During the secondcall()
, theAttacker
Contract will receive moreETH
than they deposited into the contract. If this process continued, theAttacker
Contract could bankrupt theVulnerable
Contract!
Summary
- Reentrancy is like a bank withdrawal scenario where someone requests money, but before the teller updates their balance, they jump back in line to withdraw again.
- The code demonstrates Single-Function Reentrancy, where a single function is re-entered during the attack. As you'll see in Reentrancy Fundamentals: Defend Theory, there can be other types of Reentrancy (e.g., Cross-Function Reentrancy, Cross-Contract Reentrancy, etc.)
Process Diagram
- In this section, you'll visualize how the
Attacker
Contract could exploit theVulnerable
Contract. As previously discussed, you'll create theAttacker
Contract in the next lesson. - The diagram is meant to give a high-level overview of the attack. In other words, certain minor steps are omitted. Learning how to complete these minor steps independently is a pivotal skill. As such, you'll practice this skill within the Reentrancy Fundamentals: Attack Lab.Important
- To solidify your understanding, try to cross-reference theTip
Vulnerable
Contract (in the diagram) with the Code.
Attack Diagram
Tip:
Click on the image to zoom in
Explanation
- Seeding Phase -
1
: In this example, the attack starts whenAttacker
Contract creates a balance withinVulnerable
Contract. - Transfer Phase -
2
: Note theAttacker
Contract balance (on the blockchain), is now 0ETH
. - Transfer Phase -
3a
3b
: WhenAttacker
Contract attempts to withdraw 1ETH
, theVulnerable
Contract checks to see ifAttacker
Contract has a positive balance. - Transfer Phase -
4a
4b
: The transfer moves forward becauseAttacker
Contract has 1ETH
available (inVulnerable
Contract's state). - Transfer Phase -
5
: When the developer createdVulnerable
Contract, they assumed the contract would interact with Externally Owned Accounts (i.e., accounts that don't execute code). In other words, they didn't expect Transfer Phase -5
to occur. In the developer's faulty mental model, the execution flow would immediately transition to the Deduction Phase. However, the third party is actually a smart contract and when one contract calls another, it's like temporarily handing over the steering wheel - the called contract gets to decide what happens next. When the "steering wheel" is handed to theAttacker
contract, the Deduction Phase hasn't occurred. - Transfer Phase -
3a
: After receiving the 1ETH
, theAttacker
Contract can immediately attempt another withdrawal. In other words, theAttacker
Contract is "re-entering" theVulnerable
Contract. As the Deduction Phase hasn't occurred, Transfer Phase -3b
will evaluate toTrue
and theVulnerable
Contract will transfer unintended eth to theAttacker
Contract. Unfortunately, this transfer can start the "attack loop" again (see red arrows). The "attack loop" will continue until all eth has been transferred to theAttacker
contract. - : Notice how theKey Takeaway
Vulnerable
Contract has state-changing operations (Deduction Phase) after giving execution control to theAttacker
Contract ( Transfer Phase -4a
). This is a common sign of a Reentrancy vulnerability.
Next Steps
- In the
Reentrancy Fundamentals: Attack Lab, you'll create the
Attacker
Contract and get some "hands on" experience with this vulnerability!
Real World Examples
Inspiration
We wanted to thank the following content creators. Without people like you, BlockBash tutorials couldn't exist :)
Disclosures
Warning: