The Dark Side of DeFi
Smart contract triagers at @immunefi
Interested in investigating EVM based defi hacks.
Previously worked as an appsec engineer in web2 space.
Create educational content.
@immunefi-team/community-challenges
https://immunefi.medium.com
ArbazKiraak
0xrudrapratap
Who are we
What are smart contracts
Web2 vs Web3 application architecture flow
Most common decentralized application(DAPP) vulnerabilities
Most common smart contract vulnerabilities
Outro - Get started with smart contract hacking resources
Agenda
What are smart contracts?
Immutable program code containing set of instructions to be executed.
Run on decentralized blockchain network such as Ethereum, Solana, Polkadot etc
Extensively written in high level languages like Solidity, Vyper, Rust, Stacks etc
Contains set of OPCODES which interacts with the EVM (Ethereum virtual Machine)
Web2 vs Web3 Architecture
What are these wallets?
Creates a digital identity on the blockchain.
Generates a pair of private key and public key
Private key(secp256k1) gives access to the wallet
Public key represents your address
Handles the communication between smart contracts and the frontend
Read, Write, Execute instruction
Store digital assets
Ethereum or ERC20 tokens like USDT etc
ERC721 (NFT) assets.
Other many variants.
How does authentication works?
Compared with current web2
Meant to be public in nature.
Digital signatures are used to verify the ownership of an account.
Use case: Signature owner can create a offline signature, then pass it to other user or contract that can use the signature to broadcast the transaction on behalf of the signer while paying the gas fee on behalf of the signer.
Why Signatures?
Auth Flow
1. User Initiates login and sends request to backend to create a random nonce.
2. User signs a message which contains (message + nonce) with wallet to create a unique signature.
3. Backend verifies the signature by recovering the address of signer and generate the auth token.
4. Backend expires the current nonce, so a unique nonce is created next time the user login.
Example of Auth Workflow
Missing random nonce
Signature Replay
Validator accepts arbitrary message.
{sigHash:"0xabc..",userAddr:"[victim address]"}
Logged in as victim.
Authentication Vulnerabilities
Applications that generate signatures but do not use a random nonce to generate the signatures are vulnerable to replay attacks.
No nonce is used to generate a signature therefore making it vulnerable to signature replay attacks.
Missing Random Nonce
When a cryptographic signature intended for a single use is permitted to be replayed repeatedly, leads to signature replay attacks.
If an application only verifies the user-supplied signature without validating whether the provided message and signature are the same as those required by the application to generate JWT tokens, an authentication bypass could happen.
Validator Arbitrary accepts any message
> We substituted a random signature picked from the database of Ethereum Verified Signatures for each of the three parameter
Address
Signature
and message.
> If the application is not verifying that the message signed by the user is different from what the application asked the user to sign, an attacker could produce an auth token on the victim's behalf.
Validator Arbitrary accepts any message hash
Client Side Injections
Javascript injections (XSS)
Substituting the contract addresses.
Modifying transaction arguments or parameters.
Severity stands critical considering the digital assets at risk.
source: coindesk
Decentralized finance (DeFi)
Financial ecosystem based on blockchain technology.
It’s lets users buy and sell assets and perform financial services as a form of investment or financing without middleman.
Such as Decentralized Exchange(DEX), Borrow-Lending, Yield farming, Derivatives, etc.
Common smart contract vulnerabilities
01
Unsafe external calls
03
Insecure external dependencies
02
Griefing vulnerability
External Calls
Calls to 3rd party address that we do not control
Calls to untrusted contracts can introduce several unexpected risks or errors.
External calls controlled by an attacker may force your contract to transition into an undefined state.
Types of External Calls
01
STATIC - CALL
02
DELEGATE-CALL
Re-entrancy attack (call method)
A reentrancy attack occurs when a function makes an external call to another untrusted contract
Then the untrusted contract makes a recursive callback to the vulnerable contract function to steal funds.
1. EOA (Externally Owned Accounts)
2. Smart contracts themselves
But first, Who can be the callers?
Example re-entrancy attack (call method)
How to fix this vulnerability?
Mutex locking
CEI (checks effects interaction) pattern
Comparison with CEI pattern
Reentrancy vulnerable pattern
CEI (checks effects interaction) pattern
Short intro to delegate(call)
DELEGATE CALL
setNum(5)
CONTRACT-A
CONTRACT-B
SLOT
Contract - A
Contract - B
0
5
0
1
…..
0
Execution occurs in contract B while updating the storage in contract A.
Using this method, contract can preserve the storage state while using the logic of contract.
Introduced the concept of Proxies.
Example of the delegatecall
Storage layout
SAVE STATE
Delegate(call) and proxies
The proxy contract redirects all the calls it receives to an logic contract, whose address is stored in its (Contract A’s) storage.
The proxy contract runs Contract B’s code as its own, modifying the storage and balance of Contract A.
Transparent Proxy Pattern (TPP)
upgrade logic is stored in proxy itself.
gas-inefficient.
Universal Upgradable Proxy Standard (UUPS)
upgrade logic is stored in logic itself.
gas-efficient.
Types of Proxies Patterns
By calling the upgrade function, the storage slot on the proxy contract is updated to point to a new logic contract.
Uninitialized proxy bug
Lot of developers often leave the contracts uninitialized. This is not an problem in most cases, but problematic when it leads to some major changes like: granting ownership to the caller.
Owner of the contract can upgrade the implementation contract.
This bug can lead to the self-destruction of the logic contract, which could render the proxy contracts useless.
CALL
DELEGATE CALL
(PROXY)
( DATA )
( LOGIC )
SAVE STATE
RETURN
DELEGATE CALL
( LOGIC )
SELFDESTRUCT
CALL
( PROXY)
( DATA )
DELEGATE CALL
CALL
( EVIL )
Its storage and code are erased from the blockchain.
Proxy contract is bricked.
Normal Workflow.
1. Malicious user deploys Evil contract containing SELFDESTRUCT opcode.
2. Delegate(call) to Evil contract.
SAVE STATE
UUPS pattern uninitialized proxy bug
Wormhole bridge protocol : Attacker can held the entire protocol for ransom ($1.8 billion)
$10M Bounty : https://medium.com/immunefi/wormhole-uninitialized-proxy-bugfix-review-90250c41a43a
POC: https://github.com/immunefi-team/wormhole-uninitialized
makes the caller owner
Push vs Pull Pattern
Contract with logic with transferring ether to the user.
Which involves the risk associated with transferring ether to the user as this external call could fail. If the receiving address is a contract.
it could have a fallback function implemented that simply throws an exception, once it gets called.
Another reason for failure is running out of gas.
NFT Auction Workflow (Push Pattern)
100$ BID
200$ BID
REFUND 100$
NFT AUCTION
(USER-1)
(USER-2)
https://github.com/immunefi-team/community-challenges/blob/master/contracts/vulnerable/Auction.sol
Auction Workflow (Push vs Pull)
100$ BID
200$ BID
REJECT REFUND
NFT AUCTION
Deploy
( EVIL )
(ATTACKER)
(USER)
1. Malicious user deploys Evil contract containing exception condition to revert any incoming calls.
2. Contract is forced into a Griefing state.
100$ BID
200$ BID
CLAIM 100$
NFT AUCTION
(USER-1)
(USER-2)
Push Pattern
Pull Pattern
Spot Price Dependency
Price Oracles
A price oracle is a tool used to view the price information of a given asset.
On-chain oracles rely on constant-product AMMs, like UniswapV2 or Balancer.
Users rely on the current ratio of two tokens.For example, the ETH-DAI ratio gives us the current price of an ETH.
Onchain Spot Price
Finding the price of WBTC in ETH on Uniswap V2 pair for ETH/WBTC, grab the reserve balance of ETH and WBTC, then divide the two.
X = 20 WBTC , Y = 100 ETH
P(y) = Y / X
P(y) = 100 / 20 = 5 ETH per WBTC
(Easily impact the price movement by buying and selling)
Manipulating the large volume with flash loan (considering high liquidity)
Exploiting on borrowing platform as example. (spot price dependency)
Spot Price Dependency Example
1 ETH
10 ETH,
100k USDT
Borrow 900 USDT
querying price of 1 ETH
$1000
ETH/USDT
ETH/USDT
10k USDT
10k USDT
8 ETH
10 ETH,
100k USDT
ETH/USDT
querying price of 1 ETH
$10k
Borrow 72K USDT
Supply 8 ETH
8 ETH
Inflates the price of ETH
ORACLE
ORACLE
ORACLE
VAULT
VAULT
Supply 1 ETH
Relying on TWAP (Time Weighted Average Price)
Average price between the time intervals.
M-of-N Reporters
Averaging the price between the multiple AMM products like Uniswap, MakerDAO, Balancer etc , and offchain oracle’s like chainlink.
Hard choices, but better than spot price
Lack of Access Control
Creates a griefing opportunity by disrupting the operations of the protocol.
Blacklist/Whitelist any user on the contract.
Missing Authorization Check
Sense Finance : Lack of access control updating oracle data
Anyone can call the onSwap() which updates the stored oracle information on the pool contract.
https://medium.com/immunefi/sense-finance-access-control-issue-bugfix-review-32e0c806b1a0
Fixed by adding caller check
Why bug bounties and role of Immunefi?
When code is law and code is money, then a bug that is exploited is just straight money for the exploiter.
Protecting from the biggest threats of space.