code-423n4 / 2023-04-ens-findings

0 stars 0 forks source link

resolve() function might be susceptible to a denial-of-service (DoS) attack #34

Closed code423n4 closed 1 year ago

code423n4 commented 1 year ago

Lines of code

https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnsregistrar/OffchainDNSResolver.sol#L49

Vulnerability details

Impact

In the OffchainDNSResolver contract, the resolve() function is responsible for handling DNS name resolution. It does this by interacting with the provided gatewayURL and then calling the resolveCallback() function to verify and return the appropriate response. If an attacker were to repeatedly call this function with a large number of requests, the contract could run out of gas and potentially become unresponsive.

Proof of Concept

Here's a simplified Proof of Concept (PoC) to illustrate the attack vector on the resolve() function in the OffchainDNSResolver contract. In this example, assume that an attacker has created a malicious smart contract that repeatedly calls the resolve() function in a loop, consuming gas and attempting to cause a DoS attack.

Deploy the OffchainDNSResolver contract with the necessary parameters (ENS, DNSSEC, and gatewayURL).

The attacker creates and deploys a malicious smart contract:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "./OffchainDNSResolver.sol";

contract MaliciousContract {
    OffchainDNSResolver public offchainDNSResolver;
    bytes public name = "...";
    bytes public data = "...";

    constructor(OffchainDNSResolver _offchainDNSResolver) {
        offchainDNSResolver = _offchainDNSResolver;
    }

    function attack(uint256 numRequests) public {
        for (uint256 i = 0; i < numRequests; i++) {
            try offchainDNSResolver.resolve(name, data) {} catch {}
        }
    }
}

The attacker calls the attack() function with a large numRequests value, triggering the loop that repeatedly calls the resolve() function in the OffchainDNSResolver contract:

const maliciousContract = await MaliciousContract.deployed();
await maliciousContract.attack(1000);

This PoC demonstrates how an attacker could potentially flood the resolve() function with numerous requests in a short period, causing the OffchainDNSResolver contract to consume a large amount of gas. If the attack is severe enough, it could make the contract unresponsive, preventing legitimate users from using it for DNS name resolution.

To protect the contract against such attacks, consider implementing rate-limiting or a cost mechanism, as discussed in the previous response.

Tools Used

Manual review

Recommended Mitigation Steps

A denial-of-service (DoS) attack could lead to legitimate users being unable to use the contract as intended. To mitigate this risk, you can implement the following strategies:

1 - Rate limiting: Implement a rate-limiting mechanism that restricts the number of requests a user can make within a specific time period. This can be done by maintaining a mapping of user addresses to the timestamps of their last requests. When a new request comes in, you can check the timestamp and enforce a minimum waiting time before the user can make another request.

mapping(address => uint256) lastRequestTimestamp;

function resolve(...) external view returns (bytes memory) {
    require(
        block.timestamp - lastRequestTimestamp[msg.sender] >= minWaitingTime,
        "Request rate exceeded"
    );
    lastRequestTimestamp[msg.sender] = block.timestamp;
    // ...
}

2 - Cost mechanism: Introduce a cost mechanism that requires users to pay a fee in Ether or a specific token to use the resolve() function. This would discourage excessive requests as the attacker would need to spend resources to flood the contract. The collected fees can be used to fund contract operations or distributed to the contract owner.

uint256 public constant fee = 0.01 ether;

function resolve(...) external payable returns (bytes memory) {
    require(msg.value >= fee, "Insufficient fee");
    // ...
}

These approaches can help protect the OffchainDNSResolver contract from DoS attacks by either limiting the rate of requests or making it costly for attackers to flood the contract with requests. Implementing one or both of these strategies can improve the contract's security and stability.

thereksfour commented 1 year ago

SELF-DOS, invalid.

c4-pre-sort commented 1 year ago

thereksfour marked the issue as low quality report

c4-judge commented 1 year ago

dmvt marked the issue as unsatisfactory: Invalid