Denial
1. 题目要求
1.1 这是一个简单的钱包,会随着时间的推移而流失资金。您可以成为提款伙伴,慢慢提款。
通关条件: 在owner调用withdraw()时拒绝提取资金(合约仍有资金,并且交易的gas少于1M)
1.2 题目要求
1 | // SPDX-License-Identifier: MIT |
2. 分析
tips: 参考博客
2.1这个函数做了什么:
- 设置合约的余额
amountToSend
partner
通过低级别将余额的 1% 转移到call
- 将余额的 1% 转入合约的
owner
viatransfer
withdraw
更新函数最后一次执行的时间- 更新合作伙伴提取的金额
正如我们所说,这个挑战完全是关于拒绝服务 (DOS) 的概念,这是一个通用术语,用于描述外部参与者拒绝服务的某个方面的情况。在这种特定情况下,我们要否认
withdraw
合约的过程。我们该怎么做?
call
我们唯一的选择是在外部对地址做一些坏事partner
。让我们看看底层call
在 Solidity 中是如何工作的。1
(bool success, bytes memory data) = targetAddress.call{value: <weiSent>, gas: <gasForwarded>}(<calldata>);
正如我提到的,这是一个允许您做很多事情的低级函数。通常,它用于:
value
通过在选项中指定 wei 的数量将 Ether 发送到 EAO- 通过在选项中指定 wei 的数量,将 Ether 发送到已实现
receive
or函数的合约fallback``value
- 通过将哪个函数和哪些参数传递给目标函数来调用合约函数
<calldata>
。例如,abi.encodeWithSignature("callMePlease()")
虽然这两个
transfer
高级send
函数(用于将 ETH 发送到目标地址)都使用2300 gas的硬编码量来执行操作,但该call
函数有两个选项:- 默认情况下,如果您不指定任何内容,它将转发所有剩余的交易气体
gas
否则,您可以指定外部合约可以使用参数的气体量
该
call
函数将返回两个参数:bool success
如果调用成功bytes memory data
返回值
每次你执行一个
call
你应该总是检查它是否已经成功并恢复(或处理它但是你的场景需要)如果success
值为假。有关此方面的更多信息,请参阅SWC-104:未经检查的调用返回值。无论如何,回到我们的场景。我们需要找到一种方法来在
Denial
withdraw
函数向我们发送partner
资金时对其进行 DoS。因为函数没有检查返回值(一般来说,这是一个巨大的错误,请参阅 SWC-104 问题)即使我们在调用执行中恢复
withdraw
,函数的流程也会继续。我们如何强制停止执行?我们唯一的选择是排出所有转发的气体,并由于“气体不足”异常而使智能合约恢复。
一种简单的方法是使用无限循环对状态变量执行计数器增加
- 设置合约的余额
参考视频 写的攻击合约:
1 | contract Hack { |
3. 解题
- 3.1 获取关卡实例地址:0xa22A605788d9828cb51eAd6AA5d5549cb40Da5F0
- 3.2 将实力地址作为参数,用以部署攻击合约
- 3.3 提交案例
- 3.4 成功!!!!