Posted at

tx.origin攻撃

More than 1 year has passed since last update.


要約

ユーザ認証にtx.originを使ってはいけませんというお話。


バグのあるウォレット

fallback関数による入金機能と、transferTo関数による送金機能、それとgetBalance関数による残高確認機能のみのシンプルなスマートコントラクトウォレットを作りました。

pragma solidity ^0.4.11;

// THIS CONTRACT CONTAINS A BUG - DO NOT USE
contract MyWallet {
address owner;

function MyWallet() public {
owner = msg.sender;
}

function() public payable {}

function transferTo(address _dest, uint _amount) public {
require(tx.origin == owner); // BAD
_dest.call.value(_amount)();
}

function getBalance() public view returns (uint) {
return this.balance;
}
}

transferTo関数ではrequireでこのコントラクトをインストールした自分以外の呼び出しはエラーになるようにしてあります。誰かに残高を盗まれたら困りますからね。

そして1ETHを入金しておきました。getBalance関数を呼ぶと1000000000000000000が返ってきます。


送金

なにか物を買うかして、アドレス0x0123456789abcdef0123456789abcdef01234567に10weiを送金することになりました。

transferTo(0x0123456789abcdef0123456789abcdef01234567, 10)

を実行すれば良いです。簡単ですね。


残高確認

getBalance関数を呼ぶと0が返ってきました??????


攻撃ウォレット

実はアドレス0x0123456789abcdef0123456789abcdef01234567はEOAではなくコントラクトでした。

pragma solidity ^0.4.11;

interface Wallet {
function transferTo(address _dest, uint _amount) public;
}

contract AttackWallet {
address owner;

function AttackWallet() public {
owner = msg.sender;
}

function() public payable {
Wallet(msg.sender).transferTo(owner, msg.sender.balance);
}
}

MyWalletからAttackWalletへ送金をすると、AttackWalletのfallback関数が呼ばれます。AttackWalletのfallback関数では、再度MyWalletのtransferTo関数を呼んでいます。transferTo関数で呼び出し元をチェックしているから大丈夫… と思いきや、チェックしているのはtransferTo関数の呼び出し元ではなく、tx.origin(トランザクションの呼び出し元)です。トランザクションの呼び出し元は最初にtransferTo関数を呼んだEOAアカウント、つまりMyWalletのownerなので、requireは成立してしまい、MyWalletの全ての残高はAttackWalletのownerに送金されてしまいました。


どうすれば良かったのか

この部分

        require(tx.origin == owner); // BAD

呼び出し元チェックはmsg.senderを使いましょう

        require(msg.sender == owner); // GOOD

また、 https://qiita.com/k-keisuke/items/cd2744c7ba085beff16b にあるように、送金時はaddress.call.value()()ではなく、addess.transfer()を使いましょう。後者はfallback関数で2300gasを超える処理を実行するとエラーになります。


参考

http://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin

ここのコードを若干改変

https://medium.com/coinmonks/solidity-tx-origin-attacks-58211ad95514

解説はここを参考