Ethernaut #17 Preservation Write-up

Androidエンジニアの ゆいき@yuikimil です

最近、EthernautというSolidity(EVM)のCTF的なものをやっているのですが、
一部のレベルはWrite-upが無いので書きます

Ethernautとは

Ethernautは一般的なセキュリティ分野のCTFのようにフラグを見つけるのではなく、与えられたEthereumのスマートコントラクトのStateをある条件に変更するという形式をとっている問題集です

Solidityを用いたEVM上で動くスマートコントラクトにおけるセキュリティを学ぶにはよいサイトです

Ethernautは現在Level #0から#18まであるのですが、#17まではWrite-upが存在するので、
今回はLevel #17のPreservationを解説します
問題はこちら

※これより先、解答を含みます。ご注意ください










攻撃コード

2つのコントラクトをデプロイして、Attacker#exploitを実行します

contract Attacker {
    function exploit() public {
        Preservation victim = Preservation(/* Preservation instance address */);
        victim.setSecondTime(/* MalignantLibraryContract address */);
        victim.setFirstTime(0);
    }
}

contract MalignantLibraryContract {
  uint pad1;
  uint pad2;
  address public owner;

  function setTime(uint _time) public {
      owner = tx.origin;
  }
}

解説

概要

クリア条件は、与えられたコントラクト(インスタンス)のowner変数を自分に書き換えることです

ownerを変更しているコードが全く無いため、一見不可能に見えますが、
外部コントラクトのfunctionをdelegatecallを用いて呼び出しているコードがあることがわかります
今回はここがキーとなります

delegatecallを用いて外部コントラクトを呼び出すと、呼び出し側のコンテキストで呼び出し先のコードを実行します
驚くことに、呼び出し先のコントラクトにて、呼び出し先のコントラクトのstorage変数を変更すると、
呼び出し先のコントラクトのstorage変数が変更されるわけではなく、呼び出し元のコントラクトのstorage変数が変更されます

WTF!

例えばdelegatecallを用いて呼ばれたfunction内で、そのコントラクトの一番上で定義されているstorage変数に何かしらの値を代入すると、 実際には代入されずに、 呼び出し元のコントラクトの一番上で定義されているstorage変数に代入しようとした値が実際に代入されます

フェーズ1

まずPreservation#setSecondTimeMalignantLibraryContractのアドレスを引数にして呼ぶと
LibraryContract#setTimedelegatecall経由で、つまりPreservationコントラクトのコンテキストで呼ばれるので、
Preservationコントラクト内で上から一番目に定義されているstorage変数timeZone1LibraryMalignantLibraryContractのアドレスに変更することができます

フェーズ2

次にPreservation#setFirstTimeを呼ぶと、
timeZone1LibraryMalignantLibraryContractのアドレスに変更されているので、MalignantLibraryContract#setTimeが同様に呼ばれ、
Preservationコントラクト内で上から三番目に定義されているstorage変数ownertx.originに変更されます

まとめ

Solidityを書く人は知っておいたほうが良いことなので良問ですね
それにしてもこの仕様は結構罠

参考

Hiring!

先日、弊社コーポレートサイトがリニューアルして、
代表の宇佐美からのラブレターが公開されたので、是非読んでみてください!

また、「英単語の会社からビットコインの会社になるまで」や「ミッション・バリューが決まるまで」などPARK代表の田村さんのインタビューを交えたnoteも公開されたので良ければこちらもどうぞ! note.mu

Tip me!

こういうのやってみたかったので僕のEthereumアドレス載せてみます
今回の記事、良かったなと思ったらtipお願いします🙇‍♂️
f:id:Yuiki0627:20180621173433p:plain