1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
| import subprocess import time import re from web3 import Web3 from solcx import compile_source, install_solc import os
install_solc('0.8.26')
with open("hardhat_node_output.txt", "w") as outfile: node_process = subprocess.Popen( ["npx", "hardhat", "node", "--hostname", "0.0.0.0"], stdout=outfile, stderr=subprocess.PIPE, text=True )
time.sleep(30)
with open("hardhat_node_output.txt", "r") as infile: output = infile.read()
accounts = re.findall(r'0x[a-fA-F0-9]{40}', output)
if len(accounts) < 2: node_process.kill() raise Exception("无法获取足够的账户信息")
deployer_account_address = accounts[0] attacker_account_address = accounts[1]
w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545'))
if not w3.is_connected(): node_process.kill() raise Exception("无法连接到以太坊节点")
deployer_private_key = "" attacker_private_key = ""
deployer_account = { "address": deployer_account_address, "private_key": deployer_private_key }
attacker_account = { "address": attacker_account_address, "private_key": attacker_private_key }
solidity_code = ''' // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;
contract Bank { mapping(address => uint256) public balanceOf; string private flag; uint256 public flagPrice = 50 ether;
// 事件日志 event Deposit(address indexed user, uint256 amount); event Withdraw(address indexed user, uint256 amount); event TransferFailed(address indexed user, uint256 amount); event FlagPurchased(address indexed buyer, string flag);
constructor(string memory _flag) { flag = _flag; }
// 存入ether,并更新余额 function deposit() external payable { balanceOf[msg.sender] += msg.value; emit Deposit(msg.sender, msg.value); }
// 提取msg.sender的全部ether function withdraw() external { uint256 balance = balanceOf[msg.sender]; // 获取余额 require(balance > 0, "Insufficient balance"); (bool success, ) = msg.sender.call{value: balance}(""); require(success, "Failed to send Ether"); // 更新余额 balanceOf[msg.sender] = 0; }
// 获取银行合约的余额 function getBalance() external view returns (uint256) { return address(this).balance; }
// 获取flag function getFlag() external view returns (string memory) { require(balanceOf[msg.sender] >= flagPrice, "Insufficient balance to get flag"); return flag; } }
'''
compiled_sol = compile_source(solidity_code)
contract_id, contract_interface = compiled_sol.popitem()
Bank = w3.eth.contract(abi=contract_interface['abi'], bytecode=contract_interface['bin'])
nonce = w3.eth.get_transaction_count(deployer_account["address"])
T=0 def get_flag(): while T<200: flag = os.getenv('GZCTF_FLAG') if flag is not None: return flag print("Environment variable 'GZCTF_FLAG' is not set. Waiting for 1 minute...") time.sleep(1)
flag = get_flag()
transaction = Bank.constructor(flag).build_transaction({ 'chainId': 31337, 'gas': 2000000, 'gasPrice': w3.to_wei('50', 'gwei'), 'nonce': nonce, })
signed_txn = w3.eth.account.sign_transaction(transaction, private_key=deployer_account["private_key"])
tx_hash = w3.eth.send_raw_transaction(signed_txn.rawTransaction)
tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
bank_contract_address = tx_receipt.contractAddress print(f'Bank合约部署成功,地址为: {bank_contract_address}') print(f'Bank合约ABI: {contract_interface["abi"]}') time.sleep(2) subprocess.Popen(["python3", "2.py"])
import socket
def start_tcp_server(host, port, message): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((host, port)) s.listen() print(f"Listening on {host}:{port}") while True: conn, addr = s.accept() with conn: print(f"Connected by {addr}") conn.sendall(message.encode())
message = f"Bank合约部署成功,地址与测试账号私钥为: {bank_contract_address} {attacker_account['private_key']}\n" start_tcp_server('0.0.0.0', 65432, message)
|