前言
解鎖任意帳號?
不知各位是否記得在
上一篇文章,我們在寫交易程式過程中,有對交易的內容以私鑰進行簽名。這步驟對於區塊鏈的安全性而言非常重要,這步驟可以讓礦工們驗證這則交易是否由本人所發出,他人是沒有辦法偽造這筆交易的。
但是在模擬的環境中,若我們想要模擬某個帳號的行為,或是以特定身分來取得特定智能合約的權限,這是否能夠做到的呢?Ganache能為我們達成這項需求。
接下來我們會設定一個情境來說明這項功能
跟幣安借點錢花花
在區塊鏈世界裡,相信各位對幣安(Binance)都不陌生。我們是否有辦法在我們的模擬網路中,透過幣安的帳號從它的池子裡分一些Token給我們使用?
PS. 此模擬情境不會真正的讓幣安轉錢給你,僅會在你的模擬網路中曇花一現
這樣的實驗主要是為了探討合約的安全性,若在您的實驗中有發現任何的合約漏洞,不妨將這個漏洞資訊提供給合約擁有者,為區塊鏈安全盡一份心力!
首先我們先找到其中一個幣安所使用的
帳號,我們將使用它進行範例
合約地址:0x28C6c06298d514Db089934071355E5743bf21d60
- 為了解鎖特定帳號,需要在Ganache啟動時加入以下參數(wallet.unlockedAccounts)
ganache --fork.network mainnet \
--chain.networkId 1 \
--accounts 10 \
--wallet.seed 1337 \
--port 8545 \
--wallet.unlockedAccounts 0x28C6c06298d514Db089934071355E5743bf21d60
Ganache僅能在啟動時解鎖特定帳號,現沒法在執行過程中動態解鎖帳號,有些可惜。
from web3 import HTTPProvider, Web3
import json
import time
#連線到剛啟動的Ganache RPC Server
web3 = Web3(HTTPProvider('http://127.0.0.1:8545'))
- 假如我們想要從幣安的這個帳號轉1,000USDT到我們的測試帳號,我們需要先拿到USDT合約的ABI (方式同上一篇文章所述),您一樣可以從etherscan.io得知。
#設定相關地址,userAcc和userKey為您Ganache生成的測試地址
userAcc = web3.toChecksumAddress('0xC459cc3AC9f8462Be2EF00aAD02fAc7af2e97b14')
userKey = '0xda09f8cdec20b7c8334ce05b27e6797bef01c1ad79c59381666467552c5012e3'
#USDT合約地址
USDT_ADDR = web3.toChecksumAddress('0xdac17f958d2ee523a2206206994597c13d831ec7')
#幣安錢包地址
BINANCE_ADDR = Web3.toChecksumAddress('0x28C6c06298d514Db089934071355E5743bf21d60')
- 我們可以來開始建立交易了。在ERC20的規範中,若要進行Token的轉移,您需要先approve(允許)特定金額的轉移後,才能進行transfer(轉移)。
- 首先先來導入ABI與實例化合約
#USDT合約的ABI內容請自行複製並貼到usdt.json檔案中,透過檔案內容來讀取JSON
abi = json.load(open('usdt.json'))
usdt_contract = web3.eth.contract(address=USDT_ADDR, abi=abi)
approve = usdt_contract.functions.approve(
BINANCE_ADDR, #允許哪個帳號可以進行轉移
1000 * 1000000 #允許多少
)
#我們使用幣安身分來做為FROM
txn = approve.buildTransaction({
'from': web3.toChecksumAddress(BINANCE_ADDR),
'value': web3.toWei(0,'ether'),
'gasPrice': web3.toWei('30','gwei'),
"gas": 3000000,
'nonce': web3.eth.get_transaction_count(BINANCE_ADDR)
})
#因為幣安的帳號已經被解鎖,所以可以不用對交易進行簽名,直接發送交易即可
web3.eth.send_transaction(txn)
transfer = usdt_contract.functions.transfer(
userAcc, #轉給誰
1000 * 1000000 #轉多少
)
#一樣使用幣安身分來做為FROM
txn = transfer.buildTransaction({
'from': web3.toChecksumAddress(BINANCE_ADDR),
'value': web3.toWei(0,'ether'),
'gasPrice': web3.toWei('30','gwei'),
"gas": 3000000,
'nonce': web3.eth.get_transaction_count(BINANCE_ADDR)
})
#因為幣安的帳號已經被解鎖,所以可以不用對交易進行簽名,直接發送交易即可
web3.eth.send_transaction(txn)
- 交易成功,我們可以回到Metamask中察看交易結果是不是符合預期呢?
後記
從上面的例子可以看到,經解鎖後的帳號,Ganache都不會要求交易的FROM地址進行簽名驗證了。代表我們可以對任意的地址取得任意的權限,例如:
- 某個NFT只有Owner可以進行mint,我們可以解鎖該Owner的帳號來發起mint
- 執行任意合約使用msg.sender進行權限控管的功能
- 對任意地址進行Peer to peer的ETH交易
- ...
充滿無限想像的可玩性,就待您慢慢發掘與研究。這功能對於研究某些鏈上合約的弱點非常有幫助,尤其在您沒有該合約的擁有權時。
感謝您閱讀到本系列的第三篇文章,希望這期帶來的內容對您而言也是有趣的。預計下一篇內容會針對交易於EVM中的行為做更進一步的了解,期待與您再一次的相見。
作者Steve目前任職於趨勢科技區塊鏈安全研究小組,專注於區塊鏈合約安全與與相關技術,如果喜歡我的文章,或是想獲得更多區塊鏈詐騙事件懶人包,歡迎關注
我的帳號!
另外,我已經加入由
趨勢科技防詐達人所成立的方格子專題-《區塊鏈生存守則》,在那裡我會跟其他優質的創作者一起帶大家深入瞭解區塊鏈,並隨時向大家更新區塊鏈資安事件