Solidity: Tx Origin Attacks

A transaction origin attack is form of phising attack that can drain a contract of all funds.


Points of failures

  • Using address.call.value(amount)() to transfer ether
  • Checking identity of the owner of a contract using tx.origin

Contracts

TxOriginVictim is a Smart Contract and is a wallet type contract.

pragma solidity ^0.4.18;

contract TxOriginVictim {
address owner;

function TxOriginVictim() {
  owner = msg.sender;
}
function transferTo(address to, uint amount) public {
  require(tx.origin == owner);
  to.call.value(amount)();
}
function() payable public {}

TxOriginAttack is a contract that will be used by the attacker.

pragma solidity ^0.4.18;

interface TxOriginVictim {
  function transferTo(address to, uint amount);
}
contract TxOriginAttacker {
address owner;

function TxOriginAttacker() public {
  owner = msg.sender;
}
function getOwner() public returns (address) {
  return owner;
}
function() payable public {
  TxOriginVictim(msg.sender).transferTo(owner, msg.sender.balance);
}
}
  1. User transfers ether from their Smart Contract wallet to the address of the TxOriginAttacker
  2. Ether hits the TxOriginAttacker contract and the fallback function is called, triggering:TxOriginVictim(msg.sender).transferTo(owner, msg.sender.balance)

3. The command in the fallback function will “pose” as TxOriginVictim using it’s address, msg.sender to transfer all the funds (msg.sender.balance) to the owner of the TxOriginAttacker contract

4. This works because in the TxOriginVictim contract we are checking for tx.origin NOT msg.sender

5. tx.origin is the original sender of a transaction and msg.sender is the immediate sender

6. Since the attacker has relayed the transaction using the address of TxOriginVictim, they can call the transferTo() function “posing” as the TxOriginVictim contract and pass msg.sender.balance (the entire balance of the sender) as the amount argument

7. The wallet (TxOriginVictim) checks for the origin of the transaction not the immediate sender, now TxOriginVictim will transfer all of the funds in it’s contract


Solutions

  • Never use tx.origin to check for authorisation of ownership, instead use msg.sender
  • Don’t use address.call.value(amount)(); instead use address.transfer()
  • address.transfer() will have a gas stipend of 2300 — meaning possible attacking contracts would not have enough gas for further computation other than emitting Events
  • address.transfer() also throws on failure

❤️ Like, Share, Leave your comment

If you like this post, don’t forget to like, share with your friends and colleagues and leave your comment below about the post.
And Follow me…….