Skip to content

Latest commit

 

History

History
158 lines (134 loc) · 5.82 KB

File metadata and controls

158 lines (134 loc) · 5.82 KB

TimelockController Exploit Agent


Description

This agent detects when someone with the executor role could escalate privileges and become an admin of the TimelockController. The agent is separated into four threads:

  1. First thread detects the RoleGranted(bytes32,address,address) event for the executor and creates an alert when the executor gets the proposer or admin roles.
  2. Second thread detects when the TimelockController vulnerability is exploited as it is described in the post-mortem.
  3. Third thread detects untrusted executors as it is described in the post-mortem.
  4. Fourth thread detects the RoleRevoked(bytes32,address,address) event and provides alerts in 3 different situations:
    1. The contract lost its Admin role.
    2. The function renounceRole() was used to revoke its own role.
    3. There is common RoleRevoked(bytes32,address,address) event.

Agent Flow

TimelockAgent.png

Supported Chains

  • Ethereum

Setup

You can specify roles signatures in the src/utils.py:

class Roles(Enum):
    admin = "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5"
    executor = "0xd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63"
    proposer = "0xb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1"

Alerts

  • TIMELOCK-ZERO-DELAY
    • Fired when MinDelayChange(uint256,uint256) event has newDuration argument equal to zero - this means that someone set TimelockController Minimum Delay to zero
    • Severity is always set to Info
    • FindingType is always set to Suspicious
    • Metadata:
      • contract - TimelockController address
      • tx_hash - hash of the transaction
      • old_delay - previous delay
  • TIMELOCK-EXPLOIT
    • Fired when malicious executor set Minimum Delay to zero, executes the proposal and after that schedules the proposal with the same id
    • Severity is always set to Critical
    • FindingType is always set to Exploit
    • Metadata:
      • contract - TimelockController address
      • tx_hash - hash of the transaction
      • executor - executor address
      • proposal_id - proposal id
  • TIMELOCK-PROPOSAL-LIFECYCLE-VIOLATION
    • Fired when proposal was scheduled after the execution, but Minimum Delay was not changed
    • Severity is always set to Critical
    • FindingType is always set to Suspicious
    • Metadata:
      • contract - TimelockController address
      • tx_hash - hash of the transaction
      • executor - executor address
      • proposal_id - proposal id
  • TIMELOCK-EXECUTOR-PROPOSER
    • Fired when executor gets the proposal role
    • Severity is always set to Medium
    • FindingType is always set to Suspicious
    • Metadata:
      • contract - TimelockController address
      • tx_hash - hash of the transaction
      • executor - executor address
      • initiator - initiator address
  • TIMELOCK-EXECUTOR-ADMIN
    • Fired when executor gets the admin role
    • Severity is always set to Critical
    • FindingType is always set to Suspicious
    • Metadata:
      • contract - TimelockController address
      • tx_hash - hash of the transaction
      • executor - executor address
      • initiator - initiator address
  • TIMELOCK-UNTRUSTED-EXECUTOR
    • Fired when executor has not Proposer role
    • Severity is always set to High
    • FindingType is always set to Suspicious
    • Metadata:
      • contract - TimelockController address
      • executor - executor address
  • TIMELOCK-ADMIN-REVOKED
    • Fired when contract loses its Admin role
    • Severity is always set to High
    • FindingType is always set to Suspicious
    • Metadata:
      • contract - TimelockController address
      • tx_hash - hash of the transaction
      • from - transaction sender address
  • TIMELOCK-ROLE-RENOUNCED
    • Fired when address renounced its own role
    • Severity is always set to Medium
    • FindingType is always set to Info
    • Metadata:
      • contract - TimelockController address
      • tx_hash - hash of the transaction
      • from - transaction sender address
      • role - hex-role
  • TIMELOCK-ROLE-REVOKED
    • Fired when there is normal RoleRevoke event in the log
    • Severity is always set to Medium
    • FindingType is always set to Info
    • Metadata:
      • contract - TimelockController address
      • tx_hash - hash of the transaction
      • from - transaction sender address
      • role - hex-role
      • account - target account

Requirements

  • Python: 3.10

Run the agent

npm start

Tests

This attack has not, as far as we know, been executed on chain.

You can test the agent using

npm test

There are 11 test that should pass:

  • test_returns_main_exploit_finding()
  • test_dont_return_main_finding_if_executed_after_schedule()
  • test_return_only_proposal_lifecycle_violation_finding_if_min_delay_was_not_changed()
  • test_return_zero_delay_finding()
  • test_return_executor_got_proposer_role_finding()
  • test_return_executor_got_admin_role_finding()
  • test_returns_untrusted_executor_finding()
  • test_returns_zero_findings_if_executor_has_proposer_role_and_everything_is_ok()
  • test_return_contact_lost_selfadministration_finding()
  • test_return_renounced_finding()
  • test_return_role_revoked_finding()

For these purposes, web3 and event mocks are used. You can check web3 mock in src/test/web3_mock.py and events mocks in src/test/agent_test.py