//tips
帰還日。動画クリエイターさんのクオリティが高く非常に満足。猫さんがとても可愛い。天才か。
//smart contract
早速追加したテスト用のmetamaskでrinkebyにデプロイしたコントラクトと接続してみる。
必要なのはデプロイ済みのコントラクトアドレスと加工したコントラクトのjsonのabi部分を抜粋したもの
こちらにて別のコントラクトからもインスタンス生成できた。
こちらを利用してアタック方法を考えていく。
まずはapproveを悪用できるか確認。
Approveは所得権転送許可を第三者に与えるものでこれに取り、受けてがtransferfromで他人のtokenを動かせる。
・転送先がトークンの保有者ではないこと
・対象トークンの保有者がこの関数を呼んでいる、または isApprovedForAll(owner, _msgSender()) == true であること
これがrequireとして働いているので基本的にこちらのインスタンスからはapproveができないはず。
approv関数の
Toにテスト用のアドレスを入れ、
TokenIdを1としたところ下記のようなエラーメッセージが表示された。
Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
execution reverted: ERC721: approve caller is not owner nor approved for all { "originalError": { "code": 3, "data": "0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000384552433732313a20617070726f76652063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f76656420666f7220616c6c0000000000000000", "message": "execution reverted: ERC721: approve caller is not owner nor approved for all" } }
Requireがきちんと機能している。
get approved関数をtokenid6で実行。get approveはそのtokenをtransferfromで、移動できる相手をは誰かを表している。誰もいないかと思いきやburn先となる下記のアドレスが登録されていた。これがデフォルト値になるよう。
0:
address: 0x0000000000000000000000000000000000000000
// Mapping from token ID to approved address
mapping(uint256 => address) private _tokenApprovals;
_tokenApprovalsは、そのトークンを、どのaddressがapprove済みかを記録するもの。
Approve解除の方法であるrevokeを行う方法も確認しておいた方が良さそう。
この_tokenApprovalsは複数入ることは後でメインメタマスクに戻った時に実験しておく。
safeTransforを使用して、ownerのアドレスからTokenid6を自分のアドレスに送る関数を実行。
ownerofでtokenidに対するownerが簡単に見れる。
Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
execution reverted: ERC721: transfer caller is not owner nor approved { "originalError": { "code": 3, "data": "0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000314552433732313a207472616e736665722063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f766564000000000000000000000000000000", "message": "execution reverted: ERC721: transfer caller is not owner nor approved" } }
きちんとエラー表示された。TransferFromも同様のエラーが発生。
supportsInterface()についても確認。
// @notice Introspection interface as per ERC-165 (https://github.com/ethereum/EIPs/issues/165). Returns true for any standardized interfaces implemented by this contract. We implement ERC-165 (obviously!) and ERC-721.
function supportsInterface(bytes4 _interfaceID) external view returns (bool)
{
// DEBUG ONLY
//require((InterfaceSignature_ERC165 == 0x01ffc9a7) && (InterfaceSignature_ERC721 == 0x9a20483d));
return ((_interfaceID == InterfaceSignature_ERC165) || (_interfaceID == InterfaceSignature_ERC721));
}
ERC-721に準拠したコントラクトは、ERC721とERC165のinterfaceを実装する必要。ERC165はERC721を補助するinterfaceとなる。このERC165のsupportsInterface()を使って、ERC165またはERC721を採用しているかを確認するもの。ここは飛ばすで良い。
次にOwnable.solにあるtransferOwnershipを実行。きちんとエラーで弾かれているので問題なし。onlyOwnerが効いている
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_setOwner(newOwner);
}
Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
execution reverted: Ownable: caller is not the owner { "originalError": { "code": 3, "data": "0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000204f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572", "message": "execution reverted: Ownable: caller is not the owner" } }
setBaseURIを他人が実行しても同じく上記のエラーが発生。
tokenURI関数を実行し、tokenid:6のtokenurlを表示させると、ipfsであるpitanaから参照した.jsonファイルのCIDが表示されることになる。
問題だったclaimItemもonlyOwnerを付けることできちんと上記のエラー表示させることに成功。
この実験から作成しているコントラクトの安全性が確認できた。
メインアドレスに戻り、tokenid6の売り出しをかけ、それをテスト用のmetamaskで取得させる。その際の_tokenApprovalsにopenseaのものが入っているかを確認するとともに、テストの方で取得できるかも実証しておく。
ただ、実際には、偽のapprove依頼を送りつけられ、metamaskで強引にapproveさせられて自分のNFTや資産が抜かれてしまうこともある。ここは自分で注意を払って管理する必要がある。
なるべくこの危険を減らすために、revokeのやり方を確認していく。
contract.sendTransaction({data:pwnFuncSig})についての深堀も忘れないようにする。