ENS Contest - Trust's results

Decentralised naming for web3

General Information

Platform: Code4rena

Start Date: 14/04/2023

Pot Size: $90,500 USDC

Total HM: 7

Participants: 59

Period: 14 days

Judge: LSDan

Total Solo HM: 3

Id: 232

League: ETH

ENS

Findings Distribution

Researcher Performance

Rank: 1/59

Findings: 3

Award: $23,845.89

🌟 Selected for report: 2

🚀 Solo Findings: 2

Findings Information

🌟 Selected for report: Trust

Labels

bug
2 (Med Risk)
satisfactory
selected for report
sponsor disputed
M-02

Awards

11893.0456 USDC - $11,893.05

External Links

Lines of code

https://github.com/code-423n4/2023-04-ens/blob/45ea10bacb2a398e14d711fe28d1738271cd7640/contracts/utils/HexUtils.sol#L75

Vulnerability details

Description

The hexToAddress utility parses a string into an address type.

function hexToAddress( bytes memory str, uint256 idx, uint256 lastIdx ) internal pure returns (address, bool) { if (lastIdx - idx < 40) return (address(0x0), false); (bytes32 r, bool valid) = hexStringToBytes32(str, idx, lastIdx); return (address(uint160(uint256(r))), valid); }

The issue is that in the return statement, the bytes32 type is reduced from 256 bits to 160 bits, without checking that the truncated bytes are zero. When the upper bits are not zero, the bytes32 is not a valid address and the function must return false in the second parameter. However, it instead returns an incorrect trimmed number.

The utility is used in the flow below:

proveAndClaim _claim getOwnerAddress parseRR parseString hexToAdress

The incorrect address would be returned from _claim and then used as the owner address for ens.setSubnodeOwner. This would brick the node.

function proveAndClaim( bytes memory name, DNSSEC.RRSetWithSignature[] memory input ) public override { (bytes32 rootNode, bytes32 labelHash, address addr) = _claim( name, input ); ens.setSubnodeOwner(rootNode, labelHash, addr); }

Impact

Lack of validation can lead to ENS addresses becoming permanently bricked.

Tools Used

Manual audit

Add a check for the upper 96 bits in the highlighted return statement.

Note for judge

Historically, the judge has awarded medium severity to various issues which rely on some user error, are easy to check/fix and present material risk. I respect this line of thought and for the sake of consistency I believe this submission should be judged similarly.

#0 - c4-pre-sort

2023-04-30T06:55:53Z

thereksfour marked the issue as primary issue

#1 - c4-pre-sort

2023-05-01T05:45:48Z

thereksfour marked the issue as duplicate of #198

#2 - c4-judge

2023-05-08T13:07:08Z

dmvt marked the issue as satisfactory

#3 - trust1995

2023-05-11T08:28:23Z

I strongly believe this issue is incorrectly dupped to #198. This one talks about the trimming that occurs which leads to accepting invalid addresses that are in 20-byte format. #198 discusses a lack of <= 20 bytes check, which would not solve this issue. Either they are both medium severity, or they both aren't.

#4 - dmvt

2023-05-12T12:36:29Z

Agreed. They are adjacent but have different impacts and fixes.

#5 - c4-judge

2023-05-12T12:36:34Z

dmvt marked the issue as not a duplicate

#6 - c4-judge

2023-05-12T12:36:38Z

dmvt marked the issue as selected for report

#7 - c4-sponsor

2023-06-01T08:25:28Z

Arachnid marked the issue as sponsor disputed

#8 - Arachnid

2023-06-01T08:26:16Z

The upshot of this is that if you provide an invalid address in DNS, it will be set to a (possibly different) invalid address in ENS. This can be fixed by correcting the address in DNS and calling proveAndClaim again. I would argue this should be considered minor at best.

Findings Information

🌟 Selected for report: Trust

Labels

bug
2 (Med Risk)
primary issue
selected for report
sponsor disputed
M-03

Awards

11893.0456 USDC - $11,893.05

External Links

Lines of code

https://github.com/code-423n4/2023-04-ens/blob/45ea10bacb2a398e14d711fe28d1738271cd7640/contracts/dnsregistrar/OffchainDNSResolver.sol#L104

Vulnerability details

Description

In OffchainDNSResolver, resolveCallback parses resource records received off-chain and extracts the DNS resolver address:

// Look for a valid ENS-DNS TXT record (address dnsresolver, bytes memory context) = parseRR( iter.data, iter.rdataOffset, iter.nextOffset );

The contract supports three methods of resolution through the resolver:

  1. IExtendedDNSResolver.resolve
  2. IExtendedResolver.resolve
  3. Arbitrary call with the query parameter originating in resolve()

Code is below:

// If we found a valid record, try to resolve it if (dnsresolver != address(0)) { if ( IERC165(dnsresolver).supportsInterface( IExtendedDNSResolver.resolve.selector ) ) { return IExtendedDNSResolver(dnsresolver).resolve( name, query, context ); } else if ( IERC165(dnsresolver).supportsInterface( IExtendedResolver.resolve.selector ) ) { return IExtendedResolver(dnsresolver).resolve(name, query); } else { (bool ok, bytes memory ret) = address(dnsresolver) .staticcall(query); if (ok) { return ret; } else { revert CouldNotResolve(name); } } }

The issue is that a resolver could support option (3), but execution would revert prior to the query call. The function uses supportsInterface in an unsafe way. It should first check that the contract implements ERC165, which will guarantee the call won't revert. Dynamic resolvers are not likely in practice to implement ERC165 as there's no specific signature to support ahead of time.

Impact

Resolution with custom DNS resolvers are likely to fail.

Tools Used

Manual audit

Use the OZ ERC165Checker.sol library, which addresses the issue:

function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) { // query support of both ERC165 as per the spec and support of _interfaceId return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId); }

#0 - c4-pre-sort

2023-04-30T07:01:10Z

thereksfour marked the issue as primary issue

#1 - Arachnid

2023-05-05T13:23:40Z

ERC165 support is required in order to be a valid resolver. Any resolver that doesn't support it is incorrectly implemented.

#2 - c4-sponsor

2023-05-05T13:23:45Z

Arachnid marked the issue as sponsor disputed

#3 - dmvt

2023-05-09T09:49:34Z

This is easy to protect against. Issue stands.

#4 - c4-judge

2023-05-09T09:49:46Z

dmvt marked the issue as selected for report

#5 - Arachnid

2023-05-09T14:22:02Z

There's no point building a protection for this; either way the result is a failed resolution.

#6 - dmvt

2023-05-12T12:10:05Z

The OZ implementation would guarantee that the else clause gets triggered and the error returned is understandable / sane. In this case, a very simple fix will significantly enhance the composability of the protocol and improve the experience of dev users.

#7 - Arachnid

2023-05-15T17:24:47Z

I continue to disagree this is an issue. ERC165 support is a baseline requirement for a resolver; checking it's supported is a pointless waste of gas.

#8 - IllIllI000

2023-05-17T12:39:12Z

https://github.com/code-423n4/2023-04-ens/blob/83836eff1975fb47dae6b0982afd0b00294165cf/contracts/utils/UniversalResolver.sol#L498-L510 this code shows that at least in other areas, the possibility failure is acknowledged and handled

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter