# Damn Vulnerable DeFi（该死易攻击的DeFi）- 解决方案 

By [Tabris.eth](https://paragraph.com/@tabris-eth) · 2022-03-31

---

DeFi 协议带来了在闪贷等传统金融中无法实现的新颖创新。在DeFi协议开发上同样需要考虑的新攻防方法。其中OpenZeppelin 发布了他们的[Damn Vulnerable DeFi CTF](https://www.damnvulnerabledefi.xyz/)。

这套题很简练和有趣，这是开始 DeFi 或 ETH 开发的好方法。与其他 CTF 不同，一切都在本地节点上运行，因此无需浪费时间进行设置，例如管理私钥、获取 testnet ether、将代码复制到本地机器等。试试看吧！[您可以在此 GitHub 存储库](https://github.com/TabrisEth/damn-vulnerable-defi-py)中查看我针对所有挑战的解决方案，并且与官方使用js答解不同，我使用python、brownie重新编写整套题。

其中包含的技术栈：Solidity、Web3py、Brownie、DeFi基础知识。

环境准备
----

1、安装brownie、web3py

    pipx install eth-brownie
    

2、克隆git，并且初始化brownie

    git clone TabrisEth/damn-vulnerable-defi-py
    cd damn-vulnerable-defi-py; brownie init
    

3、目录解释、进行测试

*   [contracts](https://github.com/TabrisEth/damn-vulnerable-defi-py/tree/main/contracts) 试题合约目录（无需改动这里）
    
*   [scripts](https://github.com/TabrisEth/damn-vulnerable-defi-py/tree/main/scripts) 试题brownie脚本目录
    

编辑改动所有脚本中的attack函数，例如

![](https://storage.googleapis.com/papyrus_images/abe610dc9a4ad99ce78f7c51bafc52357eaa5ac1df4cc3f17f9c549373546cfb.png)

测试：

    brownie run scripts/unstoppable.py 
    

Unstoppable（势不可挡）
-----------------

在这个挑战中，需要打破闪贷合约的功能。合约在存储变量中跟踪其可用余额，poolBalance并要求该变量等于合约的实际代币余额token.balanceOf(address(this))。

![UnstoppableLender.sol代码中](https://storage.googleapis.com/papyrus_images/c490d2af334d11bf4867feba5b7c193928bfb9d9d4d2ba0ffe82232cb13534a5.png)

UnstoppableLender.sol代码中

创建不平衡的一种简单方法是直接通过代币的transfer功能将代币发送到合约，而不使用闪贷合约的deposit功能。

![传给pool任意ether即可](https://storage.googleapis.com/papyrus_images/c1851b5d4089380d74c33acdf45442b78c03cef8552dcd527a7b352910b059d9.png)

传给pool任意ether即可

Naive receiver（天真的接收者）
----------------------

这个挑战包括一个用户合约与一个闪贷合约交互，每个闪贷合约都会收取高额费用。目标是耗尽用户的合同。

这里的问题是用户合约没有验证用户是所有者，因此任何人都可以代表该合约获得任何快速贷款。msg.sender总是闪贷合约，因为回调函数是从闪贷合约调用的。

为了在单笔交易中解决这一挑战，我们可以部署一个合约，代表用户合约反复进行闪电贷，直到其余额低于闪电贷费用。

![](https://storage.googleapis.com/papyrus_images/ff18f79d2d58b1c36b46a2daa020a0db9d8f3dd3021391c55b48bb62f42104d6.png)

Truster（委托人）
------------

这个挑战涉及另一个为 DVT 代币提供贷款的闪电贷合同，目标是窃取它们。闪贷合约接受一个自定义函数来调用和一个有效负载作为它的参数。这允许我们利用闪电贷合约调用任何可以被利用的合约函数。

首先，我们使用`0`代币的闪电贷（不需要还款）并将代币的`approve`函数作为参数传递给有效载荷，以批准我们的攻击者在后续交易中提取所有资金。这是有效的，因为`approve`执行的上下文是闪电贷款合约，因为它是调用它的人。

同样，我们可以编写一个自定义合约，将这两个步骤组合在一个函数/事务中。

![](https://storage.googleapis.com/papyrus_images/89e558582306c074843cf1c9b2df9eec7925c5a30491be3be1e249f8f99e00b8.png)

Side entrance（侧门）
-----------------

在进行闪电贷时，合约只检查合约的代_币_余额是否没有减少。我们可以进行闪电贷，并在回调中再次存入资金，这将使我们的攻击者拥有相同的余额。

![](https://storage.googleapis.com/papyrus_images/8f313d1e9d726ee1114b62d9d383f8c9fa6ebee5fbec47be7c1ad60807cc93c1.png)

The rewarder（奖励者）
=================

除了闪贷合约外，还有\*奖励合约。\*奖励合约根据快照代币余额每 5 天支付一次奖励。作为一般规则，如果某些逻辑依赖于及时的单个快照而不是连续/聚合的数据点，则可以通过闪贷来操纵它。在这里也是如此，我们可以等到奖励再次分发时，进行巨额闪电贷，将闪电贷中的所有代币存入奖励池。它的`deposit`功能是创建当前代币余额的新快照并立即分配奖励。由于我们的代币余额以及我们在奖励池中的总代币份额如此之高，整数除法导致所有其他账户都获得`0`奖励。

![](https://storage.googleapis.com/papyrus_images/3a686930b9a35e527394b7e785c65bb50ab379555ab215d191bb789078494842.png)

Selfie（自拍）
----------

本次挑战与上一次类似，接受多数代币持有者决定的治理合约可能会被闪电贷款滥用。

![首先我们需要想办法伪装为治理者为切入口](https://storage.googleapis.com/papyrus_images/0700c440af836c7e84ac1c1f99112c347aec57dbd544958a77f34958562e0982.png)

首先我们需要想办法伪装为治理者为切入口

闪电贷函数中使用call函数调用发送者的`receiveTokens`函数，可以创建攻击合约，编写此函数，调用治理合约，再调用`drainAllFunds`函数。

最终：我们攻击者成为治理令牌鲸鱼我们可以用它来排队治理行动以耗尽所有资金。

![](https://storage.googleapis.com/papyrus_images/c12ad6cd96d9e792581605462c4c03e6f25d216e426da6e3e30a6d394795afaa.png)

Compromised（妥协）
---------------

题目已编写完成，待解决方案…

---

*Originally published on [Tabris.eth](https://paragraph.com/@tabris-eth/damn-vulnerable-defi-defi)*
