01dcat

Posted on Jan 20, 2022Read on Mirror.xyz

Metroverse公发是怎么了

发生了什么?

1/19/2022也就是今天,Metroverse的publicsale。我刚好这个时候没有会议,所以打算看看是不是热的一塌糊涂。但是很奇怪Metroverse的合约啥都没有发生,就卖完了。唯一一个成功的mint是第10000个block,也就是最后一个。

https://etherscan.io/tx/0x5f25e7202691ed0b5ccabf3e0640782077f9e29643b58755e6591b5c3ef6415c

其他都去哪里了??

大神出现了

让我们看看其他都去哪儿了!

https://etherscan.io/tx/0x54993818335b0cf3e083bfddb304d1d33761e095cb92e6fcab6a41d6cdf9c612

出了什么事情?

我也不知道,这个 0x1b900a675Dbdb008718E7763cc61c592FAcfA3EF 是个什么的合约,我只好去看看它的bytecode,基本上还是不明白,为什么这个可以把这些nft都拿走。

#
#  Panoramix v4 Oct 2019 
#  Decompiled source of 0x1b900a675Dbdb008718E7763cc61c592FAcfA3EF
# 
#  Let's make the world open source 
# 
#
#  I failed with these: 
#  - unknowna893c195(?)
#  - withdrawETH()
#  - _fallback()
#  All the rest is below.
#const owner = 0x7b1af7b1ef831d1bf46314d3a579eb153f980776def storage:
  saleContractAddress is addr at storage 0
  count is uint256 at storage 1
  limit is uint256 at storage 2def count(): # not payable
  return countdef limit(): # not payable
  return limitdef saleContract(): # not payable
  return saleContractAddress#
#  Regular functions
#def setLimit(uint256 _tokenId): # not payable
  require calldata.size - 4 >=′ 32
  if 0x7b1af7b1ef831d1bf46314d3a579eb153f980776 != caller:
      revert with 0, 'Ownable: caller is not the owner'
  limit = _tokenIddef unknownafdce2ec() payable: 
  require calldata.size - 4 >=′ 64
  require cd <= 18446744073709551615
  require cd <′ calldata.size
  require ('cd', 4).length <= 18446744073709551615
  require cd * ('cd', 4).length) + 36 <= calldata.size
  require ext_code.size(saleContractAddress)
  static call saleContractAddress.0x6f2057a with:
          gas gas_remaining wei
  mem[96] = ext_call.return_data[0]
  if not ext_call.success:
      revert with ext_call.return_data[0 len return_data.size]
  require return_data.size >=′ 32
  require ext_call.return_data == bool(ext_call.return_data[0])
  require not ext_call.return_data[0]
  require ext_code.size(saleContractAddress)
  static call saleContractAddress.saleActive() with:
          gas gas_remaining wei
  mem[ceil32(return_data.size) + 96] = ext_call.return_data[0]
  if not ext_call.success:
      revert with ext_call.return_data[0 len return_data.size]
  require return_data.size >=′ 32
  require ext_call.return_data == bool(ext_call.return_data[0])
  require ext_call.return_data[0]
  if cd > 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff:
      revert with 0, 17
  require ext_code.size(saleContractAddress)
  static call saleContractAddress.totalSupply() with:
          gas gas_remaining wei
  mem[(2 * ceil32(return_data.size)) + 96] = ext_call.return_data[0]
  if not ext_call.success:
      revert with ext_call.return_data[0 len return_data.size]
  mem[64] = (4 * ceil32(return_data.size)) + 96
  require return_data.size >=′ 32
  if ext_call.return_data > !(2 * cd[36]):
      revert with 0, 17
  if ext_call.return_data * cd > 10000:
      revert with 0, 'Exceeds Max Supply'
  require count < limit
  idx = 0
  while idx < cd:
      _17 = mem[64]
      mem[mem[64] len 892] = 0xfe608060405260405161037c38038061037c833981016040819052610022916101ca565b600080826001600160a01b0316348560008151811061005157634e487b7160e01b600052603260045260246000fd5b6020026020010151604051610066919061029d565b60006040518083038185875af1925050503d80600081146100a3576040519150601f19603f3d011682016040523d82523d6000602084013e6100a8565b606091505b5091509150816100b757600080fd5b826001600160a01b0316846001815181106100e257634e487b7160e01b600052603260045260246000fd5b60200260200101516040516100f7919061029d565b6000604051808303816000865af19150503d8060008114610134576040519150601f19603f3d011682016040523d82523d6000602084013e610139565b606091505b5050505050505061032f565b80516001600160a01b038116811461015c57600080fd5b919050565b600082601f830112610171578081fd5b81516001600160401b0381111561018a5761018a610319565b61019d601f8201601f19166020016102b9565b8181528460208386010111156101b1578283fd5b6101c28260208301602087016102e9565b949350505050565b600080604083850312156101dc578182fd5b82516001600160401b03808211156101f2578384fd5b818501915085601f830112610205578384fd5b815160208282111561021957610219610319565b8160051b6102288282016102b9565b8381528281019086840183880185018c101561024257898afd5b8993505b8584101561027f5780518781111561025c578a8bfd5b61026a8d87838c0101610161565b84525060019390930192918401918401610246565b509750610290915050878201610145565b9450505050509250929050565b600082516102af8184602087016102e9565b9190910192915050565b604051601f8201601f191681016001600160401b03811182821017156102e1576102e1610319565b604052919050565b60005b838110156103045781810151838201526020016102ec565b83811115610313576000848401525b50505050565b634e487b7160e01b600052604160045260246000fd5b603f8061033d6000396000f3fe6080604052600080fdfea264697066735822122053f6501ff55f957ac07c643b9763b0d556c11ce1ec1de13a2bb98828df801aae64736f6c634300080400
      mem[mem[64] + 892] = 64
      mem[mem[64] + 956] = ('cd', 4).length
      s = 0
      t = cd[4] + 36
      u = mem[64] + 988
      v = mem[64] + (32 * ('cd', 4).length) + 988
      while s < ('cd', 4).length:
          mem[u] = v + -_17 - 988
          require cd[t] <′ calldata.size + -cd[4] - 67
          require cd[(cdt] + 36)] <= 18446744073709551615
          require cd <=′ calldata.size - cd[(cdt] + 36)]
          mem[v] = cd[(cdt] + 36)]
          mem[v + 32 len cd[(cdt] + 36)]] = call.data[cdt] + 68 len cd[(cdt] + 36)]]
          mem[cd[(cdt] + 36)] + v + 32] = 0
          s = s + 1
          t = t + 32
          u = u + 32
          v = v + ceil32(cd[(cdt] + 36)]) + 32
          continue 
      mem[_17 + 924] = saleContractAddress
      create contract with 200000000000000000 wei
                      code: mem[memem[64] + 988]
      if not create.new_address:
          revert with ext_call.return_data[0 len return_data.size]
      if idx == -1:
          revert with 0, 17
      idx = idx + 1
      continue 
  if cd > 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff:
      revert with 0, 17
  if count > !(2 * cd[36]):
      revert with 0, 17
  count += 2 * cd[36]def unknown888fdd2e(): # not payable
  require calldata.size - 4 >=′ 128
  require cd <= 18446744073709551615
  require cd <′ calldata.size
  require ('cd', 4).length <= 18446744073709551615
  require cd * ('cd', 4).length) + 36 <= calldata.size
  require cd == addr(cd)
  require cd <= 18446744073709551615
  require cd <′ calldata.size
  require ('cd', 100).length <= 18446744073709551615
  require cd('cd', 100).length + 36 <= calldata.size
  mem[96 len ('cd', 100).length] = call.data[cd('cd', 100).length]
  mem[('cd', 100).length + 96] = 0
  call addr(cd) with:
       gas gas_remaining wei
      args call.data[cd('cd', 100).length]
  if not return_data.size:
      require ext_call.success
      require ext_code.size(saleContractAddress)
      static call saleContractAddress.0x6f2057a with:
              gas gas_remaining wei
      mem[96] = ext_call.return_data[0]
      if not ext_call.success:
          revert with ext_call.return_data[0 len return_data.size]
      require return_data.size >=′ 32
      require ext_call.return_data == bool(ext_call.return_data[0])
      require not ext_call.return_data[0]
      require ext_code.size(saleContractAddress)
      static call saleContractAddress.saleActive() with:
              gas gas_remaining wei
      mem[ceil32(return_data.size) + 96] = ext_call.return_data[0]
      if not ext_call.success:
          revert with ext_call.return_data[0 len return_data.size]
      require return_data.size >=′ 32
      require ext_call.return_data == bool(ext_call.return_data[0])
      require ext_call.return_data[0]
      if cd > 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff:
          revert with 0, 17
      require ext_code.size(saleContractAddress)
      static call saleContractAddress.totalSupply() with:
              gas gas_remaining wei
      mem[(2 * ceil32(return_data.size)) + 96] = ext_call.return_data[0]
      if not ext_call.success:
          revert with ext_call.return_data[0 len return_data.size]
      mem[64] = (4 * ceil32(return_data.size)) + 96
      require return_data.size >=′ 32
      if ext_call.return_data > !(2 * cd[36]):
          revert with 0, 17
      if ext_call.return_data * cd > 10000:
          revert with 0, 'Exceeds Max Supply'
      require count < limit
      idx = 0
      while idx < cd:
          _36 = mem[64]
          mem[mem[64] len 892] = 0xfe608060405260405161037c38038061037c833981016040819052610022916101ca565b600080826001600160a01b0316348560008151811061005157634e487b7160e01b600052603260045260246000fd5b6020026020010151604051610066919061029d565b60006040518083038185875af1925050503d80600081146100a3576040519150601f19603f3d011682016040523d82523d6000602084013e6100a8565b606091505b5091509150816100b757600080fd5b826001600160a01b0316846001815181106100e257634e487b7160e01b600052603260045260246000fd5b60200260200101516040516100f7919061029d565b6000604051808303816000865af19150503d8060008114610134576040519150601f19603f3d011682016040523d82523d6000602084013e610139565b606091505b5050505050505061032f565b80516001600160a01b038116811461015c57600080fd5b919050565b600082601f830112610171578081fd5b81516001600160401b0381111561018a5761018a610319565b61019d601f8201601f19166020016102b9565b8181528460208386010111156101b1578283fd5b6101c28260208301602087016102e9565b949350505050565b600080604083850312156101dc578182fd5b82516001600160401b03808211156101f2578384fd5b818501915085601f830112610205578384fd5b815160208282111561021957610219610319565b8160051b6102288282016102b9565b8381528281019086840183880185018c101561024257898afd5b8993505b8584101561027f5780518781111561025c578a8bfd5b61026a8d87838c0101610161565b84525060019390930192918401918401610246565b509750610290915050878201610145565b9450505050509250929050565b600082516102af8184602087016102e9565b9190910192915050565b604051601f8201601f191681016001600160401b03811182821017156102e1576102e1610319565b604052919050565b60005b838110156103045781810151838201526020016102ec565b83811115610313576000848401525b50505050565b634e487b7160e01b600052604160045260246000fd5b603f8061033d6000396000f3fe6080604052600080fdfea264697066735822122053f6501ff55f957ac07c643b9763b0d556c11ce1ec1de13a2bb98828df801aae64736f6c634300080400
          mem[mem[64] + 892] = 64
          mem[mem[64] + 956] = ('cd', 4).length
          s = 0
          t = cd[4] + 36
          u = mem[64] + 988
          v = mem[64] + (32 * ('cd', 4).length) + 988
          while s < ('cd', 4).length:
              mem[u] = v + -_36 - 988
              require cd[t] <′ calldata.size + -cd[4] - 67
              require cd[(cdt] + 36)] <= 18446744073709551615
              require cd <=′ calldata.size - cd[(cdt] + 36)]
              mem[v] = cd[(cdt] + 36)]
              mem[v + 32 len cd[(cdt] + 36)]] = call.data[cdt] + 68 len cd[(cdt] + 36)]]
              mem[cd[(cdt] + 36)] + v + 32] = 0
              s = s + 1
              t = t + 32
              u = u + 32
              v = v + ceil32(cd[(cdt] + 36)]) + 32
              continue 
          mem[_36 + 924] = saleContractAddress
          create contract with 200000000000000000 wei
                          code: mem[memem[64] + 988]
          if not create.new_address:
              revert with ext_call.return_data[0 len return_data.size]
          if idx == -1:
              revert with 0, 17
          idx = idx + 1
          continue 
  else:
      mem[96] = return_data.size
      mem[128 len return_data.size] = ext_call.return_data[0 len return_data.size]
      require ext_call.success
      require ext_code.size(saleContractAddress)
      static call saleContractAddress.0x6f2057a with:
              gas gas_remaining wei
      mem[ceil32(return_data.size) + 97] = ext_call.return_data[0]
      if not ext_call.success:
          revert with ext_call.return_data[0 len return_data.size]
      require return_data.size >=′ 32
      require ext_call.return_data == bool(ext_call.return_data[0])
      require not ext_call.return_data[0]
      require ext_code.size(saleContractAddress)
      static call saleContractAddress.saleActive() with:
              gas gas_remaining wei
      mem[ceil32(return_data.size) + ceil32(return_data.size) + 97] = ext_call.return_data[0]
      if not ext_call.success:
          revert with ext_call.return_data[0 len return_data.size]
      require return_data.size >=′ 32
      require ext_call.return_data == bool(ext_call.return_data[0])
      require ext_call.return_data[0]
      if cd > 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff:
          revert with 0, 17
      require ext_code.size(saleContractAddress)
      static call saleContractAddress.totalSupply() with:
              gas gas_remaining wei
      mem[ceil32(return_data.size) + (2 * ceil32(return_data.size)) + 97] = ext_call.return_data[0]
      if not ext_call.success:
          revert with ext_call.return_data[0 len return_data.size]
      mem[64] = ceil32(return_data.size) + (4 * ceil32(return_data.size)) + 97
      require return_data.size >=′ 32
      if ext_call.return_data > !(2 * cd[36]):
          revert with 0, 17
      if ext_call.return_data * cd > 10000:
          revert with 0, 'Exceeds Max Supply'
      require count < limit
      idx = 0
      while idx < cd:
          _37 = mem[64]
          mem[mem[64] len 892] = 0xfe608060405260405161037c38038061037c833981016040819052610022916101ca565b600080826001600160a01b0316348560008151811061005157634e487b7160e01b600052603260045260246000fd5b6020026020010151604051610066919061029d565b60006040518083038185875af1925050503d80600081146100a3576040519150601f19603f3d011682016040523d82523d6000602084013e6100a8565b606091505b5091509150816100b757600080fd5b826001600160a01b0316846001815181106100e257634e487b7160e01b600052603260045260246000fd5b60200260200101516040516100f7919061029d565b6000604051808303816000865af19150503d8060008114610134576040519150601f19603f3d011682016040523d82523d6000602084013e610139565b606091505b5050505050505061032f565b80516001600160a01b038116811461015c57600080fd5b919050565b600082601f830112610171578081fd5b81516001600160401b0381111561018a5761018a610319565b61019d601f8201601f19166020016102b9565b8181528460208386010111156101b1578283fd5b6101c28260208301602087016102e9565b949350505050565b600080604083850312156101dc578182fd5b82516001600160401b03808211156101f2578384fd5b818501915085601f830112610205578384fd5b815160208282111561021957610219610319565b8160051b6102288282016102b9565b8381528281019086840183880185018c101561024257898afd5b8993505b8584101561027f5780518781111561025c578a8bfd5b61026a8d87838c0101610161565b84525060019390930192918401918401610246565b509750610290915050878201610145565b9450505050509250929050565b600082516102af8184602087016102e9565b9190910192915050565b604051601f8201601f191681016001600160401b03811182821017156102e1576102e1610319565b604052919050565b60005b838110156103045781810151838201526020016102ec565b83811115610313576000848401525b50505050565b634e487b7160e01b600052604160045260246000fd5b603f8061033d6000396000f3fe6080604052600080fdfea264697066735822122053f6501ff55f957ac07c643b9763b0d556c11ce1ec1de13a2bb98828df801aae64736f6c634300080400
          mem[mem[64] + 892] = 64
          mem[mem[64] + 956] = ('cd', 4).length
          s = 0
          t = cd[4] + 36
          u = mem[64] + 988
          v = mem[64] + (32 * ('cd', 4).length) + 988
          while s < ('cd', 4).length:
              mem[u] = v + -_37 - 988
              require cd[t] <′ calldata.size + -cd[4] - 67
              require cd[(cdt] + 36)] <= 18446744073709551615
              require cd <=′ calldata.size - cd[(cdt] + 36)]
              mem[v] = cd[(cdt] + 36)]
              mem[v + 32 len cd[(cdt] + 36)]] = call.data[cdt] + 68 len cd[(cdt] + 36)]]
              mem[cd[(cdt] + 36)] + v + 32] = 0
              s = s + 1
              t = t + 32
              u = u + 32
              v = v + ceil32(cd[(cdt] + 36)]) + 32
              continue 
          mem[_37 + 924] = saleContractAddress
          create contract with 200000000000000000 wei
                          code: mem[memem[64] + 988]
          if not create.new_address:
              revert with ext_call.return_data[0 len return_data.size]
          if idx == -1:
              revert with 0, 17
          idx = idx + 1
          continue 
  if cd > 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff:
      revert with 0, 17
  if count > !(2 * cd[36]):
      revert with 0, 17
  count += 2 * cd[36]

你都到这了,我们还是往下看看吧

我们只看这个unknown888fdd2e,这个就是这位大神的思路,当然我不是smartcontract的expert,我也就是大概说说想法,注意我高亮的地方:

  1. checkWhietlist
  2. saleActive
  3. 计算要多少个钱包,每个钱包mint两个
  4. 创建contract去call 这段mem[mem[64] len 892] 代码,如果没有猜错就是创建钱包和mintnft了

剩下的问题是为什么这个contract可以改官方contract里面的数据?

我们再来看看官方如何开始公售的

https://etherscan.io/address/0xc932d6a49d2d8b77b4075e537d142ee6cc1e416a

这个就是官方的call,这个时候科学家把里面的签名拿了,完全一样的call了自己的contract,如果没有猜错,科学家把官方的tx拿到了,然后加大gas,运气好了就赢了。

bonus point: 这儿必须要check owner亚

function mintNFT(uint256 amount, bool stake) public payable {         require(!checkWhitelist, "Not public mode");          _mintNFT(amount, "", "", stake);     
}

但是也有可能他有别的方式保证自己的成功率,但是我们还没有看出来。

结论

在mint的时候还是要检查owner亚。。。

本来了项目方使用Gnosis来做多重签名是好的,但是这个没有办法避免tx跟监听,然后先做了。应用的场景完全不对了。

Originally published at https://01dcat.notion.site.