09.业务逻辑漏洞
2023-06-23 20:42:14
# 00.security
业务逻辑漏洞
这个合约原本想要的逻辑是这样的:
- 我去调用83行的vote进行投票。传入一个yays,yays是yes的复数,即我需要传入一个数组,记录我要投谁票,比如传入1-3-4-7-9。
- 然后vote调用etch,将我们传入是数组进行hash,记录这个hash。第一个require:投票数不可以超过一定值,第二个require:你要按顺序传入,比如:1-3-4-7-9不可以写成1-4-3-7-9。
- 再调用91行的vote:下一次投票之前减去上一次投票的权重。有多少权重就投多少票,然后传入全局变量中。
但是我们有一个攻击的逻辑思路:
bytes32 hash = keccak256(abi.encodePacked(yays))
我们在链下就可以算出。即:提案库的索引我们可以提前算出来- 我们要攻击一个之前已经投过票的提案。比如我们要攻击提案7,我们需要预先准备一个提案1998(乱编的)。我们把提案7和提案1998拼在一起作为yays。yays我们可以提前算出来(假设算出的值是A)
- 把A作为参数调用91行的vote方法。也就是说,我们可以不通过86,87行的代码,就可以算出91行的形参。我们在链下就可以做到链上的操作。
- 因为我们1998这个提案并不存在提案库当中
- 因为提案1998根本不存在,因此
addWeight
和subWeight
算出来的yays为0。因此票数不会增加也不会减少 - 到这一步为止,我们完成的事情:votes[msg.sender] = slate:将这个值设置为我们提前算出来的索引,这个索引在提案库中根本不存在。
- 然后我们调用etch,将我们提前算出来的索引塞进
slates[hash] = yays
。这就形成了一个局面:提案库中的索引指向:提案7和根本不存在的提案1998,并且这个索引没人投过票 - 调用free方法。因为我们调用了free方法,假设我们直接将这个提案7的票数退票至0,退了其他人的票。那么其他人调用free方法退票的时候,就会卡死在free方法的地64行代码中(因为两个数相减是负数,报错,回滚)。
- 造成了投过票的用户无法收回选票!