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:
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.
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.
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.
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:
The attacker calls the attack() function with a large numRequests value, triggering the loop that repeatedly calls the resolve() function in the OffchainDNSResolver contract:
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.
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.
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.