ENS contest - csanuragjain's results

Decentralised naming for wallets, websites, & more.

General Information

Platform: Code4rena

Start Date: 12/07/2022

Pot Size: $75,000 USDC

Total HM: 16

Participants: 100

Period: 7 days

Judge: LSDan

Total Solo HM: 7

Id: 145

League: ETH

ENS

Findings Distribution

Researcher Performance

Rank: 7/100

Findings: 4

Award: $2,583.61

🌟 Selected for report: 1

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: csanuragjain

Also found by: GimelSec, cccz

Labels

bug
2 (Med Risk)

Awards

937.2294 USDC - $937.23

External Links

Lines of code

https://github.com/code-423n4/2022-07-ens/blob/main/contracts/ethregistrar/ETHRegistrarController.sol#L201 https://github.com/ensdomains/ens-contracts/blob/master/contracts/wrapper/NameWrapper.sol#L271

Vulnerability details

Impact

The ETHRegistrarController is calling renew from base registrar and not through Namewrapper. This means the fuses for the subdomain will not be updated via _setData. This impacts the permission model set over subdomain and could lead to takeover


Proof of Concept

  1. Observe the renew function
function renew(string calldata name, uint256 duration) external payable override { ... uint256 expires = base.renew(uint256(label), duration); .... }
  1. As we can see this is calling renew function of Base Registrar instead of NameWrapper. Since this is not going via NameWrapper fuses will not be set

  2. Also since renew in NameWrapper can only be called via Controller which is ETHRegistrarController so there is no way to renew subdomain


The ETHRegistrarController must renew using Namewrapper's renew contract

#0 - Arachnid

2022-07-27T03:15:55Z

Duplicate of #223.

#1 - dmvt

2022-08-03T11:01:04Z

On #223, which I've invalidated, @Arachnid notes that:

In fact, this should only be severity QA, as it can be worked around by calling renew on the registrar controller followed by setChildFuses.

I'm going to make this report the main one and leave the risk rating of Medium in place. While there is a workaround, if the workaround is not employed, permissions will be incorrect and may lead to a breakdown in the functioning of the protocol.

Findings Information

🌟 Selected for report: GimelSec

Also found by: csanuragjain

Labels

bug
duplicate
2 (Med Risk)

Awards

1562.0489 USDC - $1,562.05

External Links

Lines of code

https://github.com/code-423n4/2022-07-ens/blob/main/contracts/dnssec-oracle/DNSSECImpl.sol#L186

Vulnerability details

Impact

The RRSIG RR's Signer's Name field could differ from name of the RRSIG record due to incorrect checks

Proof of Concept

  1. Assume name of RRSIG record is abc and RRSIG RR's Signer's Name is bc

  2. In verifySignature it is checked that the RRSIG RR's Signer's Name field MUST be the name of the zone that contains the RRset

if(rrset.signerName.length > name.length || !rrset.signerName.equals(0, name, name.length - rrset.signerName.length)) { revert InvalidSignerName(name, rrset.signerName); }
  1. In our case it should not match as both are different but they will as we see below

  2. Since signerName is bc so rrset.signerName.length is 2. Similarly name of RRSIG record is abc so name.length is 3

  3. So length comparison gets false since 2>3 is false, passing first hurdle

  4. name.length - rrset.signerName.length will become 3-2=1 so name offset becomes 1

  5. This means equal comparison becomes like

rrset.signerName.equals(0, name, 1))
  1. This checks bc=bc which is true and hence the validation passes even though names are different

Revise if condition to fail if signer name length is not equal to name length

if(rrset.signerName.length != name.length || !rrset.signerName.equals(0, name, 0))

#0 - Arachnid

2022-07-27T02:45:34Z

Duplicate of #207

Default proof is returned when input is empty

Contract: DNSSECImpl.sol

Description:

  1. If submitRRSets function is called with an empty list of RRSets then no RRSet gets submitted.
  2. Instead of throwing an error that input is empty, function simply the proof (The DNSKEY or DS) which was passed as argument

Recommendation: Add below check

require(input.length>0, "No RRSET to submit");

2 step owner change

Contract: Owned.sol

Description: The setOwner function directly sets the new owner value passed without checking for 0 address or performing a 2 step change

Recommendation: Add a zero address change. Also add 2 step change for Admin which includes pendingAdmin inclusion


Use call instead of transfer

Contract ETHRegistrarController.sol

Description It was observed that withdraw function is using transfer function instead of call for transferring ether. This could become a problem if owner is contract and require more than 2300 gas (in which case transfer reverts)

Recommendation Use call which does not have 2300 gas limitation

#0 - jefflau

2022-07-22T09:50:51Z

Duplicate of #133

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