前言
- 双十一哈皮🐶
- https://blockchain-ctf.securityinnovation.com/#/
- 做了一遍,感觉这个网站上面的题目可能更贴近实际一些,新手小白刷完 https://ethernaut.openzeppelin.com/ 之后,可以选择性来做这个网站的题目
- 难度还是有的,还有很多小
trick
,目前上面是13
道题目 - 看了《数码宝贝:最后的进化》,爷青结,然后发现好久没做题了,熟悉一下做题,大佬勿喷,不是
WP
,随便写一下 - 很多是参考了网上的
wp
的内容 懒癌患者 :)
Donation
- 直接调用
withdrawDonationsFromTheSuckersWhoFellForIt
函数即可
Lock Box
- 考点是
EVM
中storage
存储的读取
1 | await web3.eth.getStorageAt(ContractAddress, "1", function(x,y){console.info(y);}) |
Piggy Bank
- 考点是继承,重写的
collectFunds
函数实际上覆盖了PiggyBank
中的同名函数 - 直接调用
collectFunds(piggyBalance)
即可
SI Token Sale
- 溢出漏洞
balances[msg.sender] += _value – feeAmount
- 只要传入一个小于
feeAmount
的_value
,即可让我们的balances
下溢,比如发送1 gas
,然后即可调用refundTokens
函数将合约的余额清空,因为这里是将_value
除2
得到提取的余额,所以我们将合约的etherCollection
乘2
作为_value
即可
Secure Bank
MembersBank
合约跟SecureBank
合约的withdraw
函数的参数类型不同,一个的_value
是uint8
,另一个却是uint256
,这样这两个函数的签名就不相同了,在合约里也就是两个不同的函数,不过它们使用super.withdraw
最终都会调用SimpleBank
的withdraw
函数MembersBank
中仅需要是注册用户即可,所以这题的流程就是先调用register
函数注册一下,然后使用etherscan
在挑战合约的创建交易里查看一下合约的创建者,因为合约的ether
都存在了它的账户上,然后我们直接使用这个地址来调用MembersBank
中的withdraw
函数即可,也就是找到参数类型为uint256
的函数
Lottery
- 随机数预测
1 | contract attack { |
Heads or Tails
- 随机数漏洞
- 每次猜对可以获得赌注的
1.5
倍,因为每次下注只能为0.1 ether
,所以一次的收益为0.05 ether
,要将合约的ether
清空需要20
次,那么我们直接在合约中循环调用20
次即可
1 | contract attack { |
Record Label
- 调用
withdrawFundsAndPayRoyalties
函数时会将对应的_withdrawAmount
全部发送至Royalties
合约,而Royalties
会将其中的80%
发送给创建者,剩下的20%
发回去,接着withdrawFundsAndPayRoyalties
中又会将这20%
发送给我们 - 所以我们直接将
_withdrawAmount
设为1 ether
来调用withdrawFundsAndPayRoyalties
函数即可
Trust Fund
- 重入漏洞
1 | contract attack { |
Slot Machine
selfdestruct
不会触发fallback payable
函数
Rainy Day Fund
- 这个题目也挺有意思,考点是
create
的计算方式,提前向可预测的地址转账 - 合约账户部署合约,
nonce
从1
开始计算 - 外部账户部署合约,
nonce
从0
开始计算
Raffle
blockhash
这个函数,它可以获取给定的区块号的hash
值,但只支持最近的256
个区块,不包含当前区块,对于256
个区块之前的函数将返回0
- 触发
fallback
函数后,若fallback
函数中又调用了自身函数,那么此时,msg.sender
变成了自身 - 所以先调用
buyTicket
,然后ctf_challenge_add_authorized_sender
认证题目合约地址(这是因为接下来会触发fallback
函数修改了msg.sender
),接着等待256
个区块后触发fallback
函数中msg.value=0
这条分支调用closeRaffle
函数,最后调用collectReward
即可
Scratchcard
- 这道题我做的很简单,简单分析了一下题目的逻辑,大致得到必须得是第三方合约和其交互,并且只能在构造函数中完成功能逻辑,所以我就去链上找记录去了2333,成功找到一个别人做过的合约地址 0xD38308cb90F17a5aB1B4DD805f69Eb5798536Eea,完美,然后查看其内部交易(因为是第三方合约与题目进行交互,所以是内部交易),点开交易即可看到
Input Data
1 | 0x60806040526040516020806102c08339810180604052810190808051906020019092919050505060006402540be4006305f5e1004281151561003d57fe5b0602600081905550600190505b601981111515610113578173ffffffffffffffffffffffffffffffffffffffff1660005460405180807f706c617928290000000000000000000000000000000000000000000000000000815250600601905060405180910390207c01000000000000000000000000000000000000000000000000000000009004906040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160006040518083038185885af1935050505050808060010191505061004a565b8173ffffffffffffffffffffffffffffffffffffffff1660405180807f636f6c6c6563744d6567614a61636b706f742875696e74323536290000000000815250601b01905060405180910390207c010000000000000000000000000000000000000000000000000000000090046730927f74c9de00006040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808267ffffffffffffffff1681526020019150506000604051808303816000875af19250505050505060d2806101ee6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a035b1fe14604b578063fc4333cd146073575b005b348015605657600080fd5b50605d6087565b6040518082815260200191505060405180910390f35b348015607e57600080fd5b506085608d565b005b60005481565b3373ffffffffffffffffffffffffffffffffffffffff16ff00a165627a7a72305820657390e5500a8446cf4b6fedd6a0ea0a1c3824339e44080120130ef94540ff5d0029000000000000000000000000428c0e1d593d7b85253f2dcf48bfb7626d7ce7e2 |
- 然后我把
Input Data
中换成我自己的题目合约地址就行了(在字节码的最后) - 然后按照
create
计算地址方法,计算出我自己外部账户部署此攻击合约的地址0xf297e7d46bdc54cdfa1cfda71e7ff0368f416705
, 提前进行ctf_challenge_add_authorized_sender
认证
1 | import rlp |
- 最后将攻击合约部署即可
1 | from web3 import Web3, HTTPProvider |
- 完美,偷懒不愧是我,这里就不具体分析题目了,有兴趣的自行分析