DEV Community

Cover image for Tornado Cash Hack: 1M $ vanished ⁉️
yagnadeepxo
yagnadeepxo

Posted on

Tornado Cash Hack: 1M $ vanished ⁉️

On may 21-2023, attacker deployed malicious code which was able to withdraw 100,000 TORN tokens worth nearly 1M $.
Let's breakdown how the hacker was able to exploit.

The hacker proposed changes to the Tornado cash governance smart contract and provided with a legitimate code which the community accepted. But later the hacker removed the legitimate code and deployed malicious code to the same address which was approved by the community, but the community members were not aware of this code change and the hacker exploited.

Let's understand how the hacker was able to deploy the smart contract to the same address

flow chart

The hacker created a root contract which deployes a deployer contract with the help of create2 opcode, the opcode is used to determine the address of the smart contract before deploying and the address of this contract is independent of nonce(no. of previous transactions made from the account).

The normal create opcode uses address of the deployer and nonce to create the address of the smart contract

contract_address = sha3(RLP(deployer address, nonce))

Deployer address and nonce is RLP(recursive length prefix) encoded and hashed.Here the contract address is dependent on the nonce, if the nonce is different the contract address is also different

create2 opcode is independent of nonce and uses salt(random hexadecimal) of user choice to compute the contract address.

contract address is calculated as

contract_address = sha3(0xFF, sender, salt, bytecode)

  • 0xFF, a constant that prevents collisions with CREATE.
  • The sender’s own address.
  • salt(random value)
  • bytecode of root contract

so the deployer contract is deployed at 0xABC

after that with the help of the deployer contract the hacker deploys a legitimate governance contract to 0xFFF address using create opcode and now the nonce of the deployer contract is set to 1, because a transaction is made, now the commuunity members approved this contract and its address.

Now hacker deleted the deployer contract and legitimate contract. Later he deployed the deployer contract again with create2 opcode using root contract, so now the nonce of the deployer contract is again set to 0 and deployed at the same address(0xABC).

With the help of the deployer contract the hacker deployed malicious contract to the approved address(0xFFF).

The malicious contract had functionalities where it was able to grant the hacker 1,200,000 votes and got access to the withdraw function of the Tornado cash smart contract and was able to withdraw the funds using delegate call

Delegatecall is a low-level function in Solidity that allows a contract to call another contract's function, but with the context of the original contract. This means that the original contract's storage, msg.sender, and msg.value are used when the called contract is executed.

Let's take an example of how delegate call can be used to withdraw funds from other contract

pragma solidity ^0.8.0;

contract Malicious {
    address payable public contractB;

    constructor(address payable _contractB) {
        contractB = _contractB;
    }

    function withdrawFromContractB() public {
        (bool success, ) = contractB.delegatecall(abi.encodeWithSignature("withdraw()"));
        require(success, "Withdraw failed");
    }
}

Enter fullscreen mode Exit fullscreen mode

The malicious contract has a delegatecall which calls the withdraw function in the Tornado cash governance contract.

pragma solidity ^0.8.0;

contract Governance {
    address public owner;
    uint public balance = 10 ether;

    constructor() {
        owner = msg.sender;
    }

    function withdraw() external {
        require(msg.sender == owner, "Only the owner can withdraw");
        require(balance > 0, "Insufficient balance");

        uint amount = balance;
        balance = 0;
        payable(msg.sender).transfer(amount);
    }
}

Enter fullscreen mode Exit fullscreen mode

The code used here is just for educational purpose.

In conclusion, the recent DeFi hack serves as a stark reminder of the risks and vulnerabilities that exist within the decentralized finance ecosystem. The breach not only resulted in a significant financial loss but also raised concerns about the security of smart contracts and the potential for exploitation.

Top comments (0)