有些人总喜欢玩触发时生成随机数的玩法,那就别怪别人玩输的吃土了。
本文是 RACA 盲盒被人用智能合约输的吃土玩成明盒的事故复盘。
事故现场
BSCScan
发生了啥
由于 RACA 的智能合约在开盲盒的时候才决定盲盒内容(自己用 Panoramix 看),
因此我们的攻击者搞了个非常简单的办法弄死了这个盲盒:只要不断的开盒,大奖就会在眼前延伸,不要停下来啊!
具体代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| def unknown3829d282(uint256 _param1): require calldata.size - >=′ 32 if not stor1[caller]: revert with 0, 'white only' require ext_code.size(0x4eb7ddd1b0103349fd289c5a4e4b95a0cc68d19e) call 0x4eb7ddd1b0103349fd289c5a4e4b95a0cc68d19e.open(uint256 param1) with: gas gas_remaining wei args _param1 if not ext_call.success: revert with ext_call.return_data[0 len return_data.size] require ext_code.size(0x61c6eeca7b14cf4ec1b190dd879008dd7d7e470) static call 0x61c6eeca7b14cf4ec1b190dd879008dd7d7e470.balanceOf(address tokenOwner) with: gas gas_remaining wei args this.address if not ext_call.success: revert with ext_call.return_data[0 len return_data.size] require return_data.size >=′ 32 if ext_call.return_data[0] != 1: revert with 0, 'no valid'
|
攻击过程
从上面合约代码可以看出,攻击者操作十分简单,不断重复开盒,如果不是大奖则输的吃土,撤销交易。又因为原合约可以重复开盒改变结果,所以盲盒变明盒
结论
在区块链这种能撤销交易的环境下,不要在交易的那一刻决定随机数结果,请集中决定盲盒结果(这样反复开盒就成了浪费Gas),或是多少个周期集中派发一次。
永远记住,EVM上单个交易是可撤销的。