|
| 1 | +# Exercise 8 |
| 2 | + |
| 3 | +**Table of contents:** |
| 4 | + |
| 5 | +- [Exercise 8](#exercise-8) |
| 6 | + - [Setup](#setup) |
| 7 | + - [Context](#context) |
| 8 | + - [Goals](#goals) |
| 9 | + - [Hints](#hints) |
| 10 | + - [Solution](#solution) |
| 11 | + |
| 12 | +Join the team on Slack at: https://empireslacking.herokuapp.com/ #ethereum |
| 13 | + |
| 14 | +## Setup |
| 15 | + |
| 16 | +1. Clone the repo: `git clone https://github.com/crytic/damn-vulnerable-defi-echidna` |
| 17 | +2. install the dependencies via `yarn install`. |
| 18 | + |
| 19 | +## Context |
| 20 | + |
| 21 | +The challenge is described here: https://www.damnvulnerabledefi.xyz/challenges/5.html, we assume that the reader is familiar with it. |
| 22 | + |
| 23 | +## Goals |
| 24 | + |
| 25 | +- Setup the testing environment with the right contracts and necessary balances. |
| 26 | +- Analyze the before function in `test/the-rewarder/the-rewarder.challenge.js` to identify what initial setup needs to be done. |
| 27 | +- Add a property to check whether the attacker can get almost whole reward (let us say more than 99 %) from the `TheRewarderPool` contract. |
| 28 | +- Create a `config.yaml` with the necessary configuration option(s). |
| 29 | +- Once Echidna finds the bug, .... well, this time to fix the issue would mean to apply completely different reward logic as in this particular solution is rather naive implementation. |
| 30 | + |
| 31 | +Only the following contracts are relevant: |
| 32 | + |
| 33 | +- `contracts/the-rewarder/TheRewarderPool.sol` |
| 34 | +- `contracts/the-rewarder/FlashLoanerPool.sol` |
| 35 | + |
| 36 | +## Hints |
| 37 | + |
| 38 | +We recommend to first try without reading the following hints. The hints are in the [`hints` branch](https://github.com/crytic/damn-vulnerable-defi-echidna/tree/hints). |
| 39 | + |
| 40 | +- The invariant that we are looking for is "an attacker cannot get almost whole amount of rewards" |
| 41 | +- Read what is the [multi abi option](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/common-testing-approaches.md#external-testing) |
| 42 | +- A template is provided in [contracts/the-rewarder/EchidnaRewarder.sol](https://github.com/crytic/damn-vulnerable-defi-echidna/blob/hints/contracts/the-rewarder/EchidnaRewarder.sol) |
| 43 | +- A config file is provided in [the-rewarder.yaml](https://github.com/crytic/damn-vulnerable-defi-echidna/blob/hints/the-rewarder.yaml) |
| 44 | + |
| 45 | +## Solution |
| 46 | + |
| 47 | +This solution can be found in [`solutions` branch](https://github.com/crytic/damn-vulnerable-defi-echidna/blob/solutions/contracts/the-rewarder/EchidnaRewarder.sol). |
| 48 | + |
| 49 | +[ctf]: https://www.damnvulnerabledefi.xyz/ |
| 50 | + |
| 51 | +<details> |
| 52 | +<summary>Solution Explained (spoilers ahead)</summary> |
| 53 | + |
| 54 | +The goal of the rewarder challenge is to realize that an arbitrary user can call request a flash loan from `FlashLoanerPool` and borrow the whole amount of Damn Valuable Tokens (DVT) available. Then this amount of DVT can deposit into `TheRewarderPool`. By doing this, the user affects total proportion of tokens deposited in the `TheRewarderPool` (and thus gets the most of the percentage of deposited asset in that particular time on his/her side). Furthermore, if the user schedules it in the right time (once the `REWARDS_ROUND_MIN_DURATION` is reached), snapshot of users deposits is taken, the user repay immediately the loan (i.e., in the same transaction) and gets almost whole reward in return. |
| 55 | +In fact, this can be done even if the arbitrary user has no DVT. |
| 56 | + |
| 57 | +Echidna reveals this vulnerability by finding the right order of two function, simply calling (1) `TheRewarderPool.deposit()` (with prior approval) and (2) `TheRewarderPool.withdraw()` with the max amount of DVT borrowed in flash loan in both functions mentioned. |
| 58 | + |
| 59 | +See example output below from Echidna: |
| 60 | + |
| 61 | +```bash |
| 62 | +$ echidna-test . --contract EchidnaRewarder --config ./the-rewarder.yaml |
| 63 | +... |
| 64 | + |
| 65 | +testRewards(): failed!💥 |
| 66 | + Call sequence: |
| 67 | + *wait* Time delay: 441523 seconds Block delay: 9454 |
| 68 | + setEnableDeposit(true) from: 0x0000000000000000000000000000000000030000 |
| 69 | + setEnableWithdrawal(true) from: 0x0000000000000000000000000000000000030000 |
| 70 | + flashLoan(39652220640884191256808) from: 0x0000000000000000000000000000000000030000 |
| 71 | + testRewards() from: 0x0000000000000000000000000000000000030000 |
| 72 | + |
| 73 | +... |
| 74 | +``` |
| 75 | + |
| 76 | +</details> |
0 commit comments