Socket Gateway - 代币交换逻辑漏洞
字数 1831 2025-08-18 11:35:59

Socket Gateway 代币交换逻辑漏洞分析报告

1. 事件概述

2024年1月17日,Socket Gateway智能合约由于performAction函数中存在逻辑漏洞,导致约330万美元的损失。攻击者利用该漏洞转移了用户的USDC、USDT、WETH、WBTC、DAI和MATIC等代币,并将其转换为ETH获利。

2. 关键地址信息

  • 攻击者地址: 0x50DF5a2217588772471B84aDBbe4194A2Ed39066
  • 被攻击合约地址: 0x3a23F943181408EAC424116Af7b7790c94Cb97a5
  • 漏洞合约地址: 0xCC5fDA5e3cA925bd0bb428C8b2669496eE43067e
  • 攻击交易示例: 0xc6c3331fa8c2d30e1ef208424c08c039a89e510df2fb6ae31e5aa40722e28fd6
  • 攻击合约地址: 0xf2D5951bB0A4d14BdcC37b66f919f9A1009C05d1

3. 漏洞背景

Socket Gateway的Admin在1月13日执行了addRoute函数添加了新的routeAddress。新部署的合约中的performAction函数存在逻辑错误,该函数原本设计用于ETH与WETH的代币交换。

4. 漏洞代码分析

4.1 漏洞函数代码

function performAction(
    address fromToken,
    address toToken,
    uint256 amount,
    address receiverAddress,
    bytes32 metadata,
    bytes calldata swapExtraData
) external payable override returns (uint256) {
    uint256 _initialBalanceTokenOut;
    uint256 _finalBalanceTokenOut;
    
    // Swap Native to Wrapped Token
    if (fromToken == NATIVE_TOKEN_ADDRESS) {
        _initialBalanceTokenOut = ERC20(toToken).balanceOf(socketGateway);
        (bool success, ) = toToken.call{value: amount}(swapExtraData);
        if (!success) {
            revert SwapFailed();
        }
        _finalBalanceTokenOut = ERC20(toToken).balanceOf(socketGateway);
        require(
            (_finalBalanceTokenOut - _initialBalanceTokenOut) == amount,
            "Invalid wrapper contract"
        );
        // Send weth to user
        ERC20(toToken).transfer(receiverAddress, amount);
    } else {
        _initialBalanceTokenOut = address(socketGateway).balance;
        // Swap Wrapped Token To Native Token
        ERC20(fromToken).safeTransferFrom(
            msg.sender,
            socketGateway,
            amount
        );
        (bool success, ) = fromToken.call(swapExtraData);
        if (!success) {
            revert SwapFailed();
        }
        _finalBalanceTokenOut = address(socketGateway).balance;
        require(
            (_finalBalanceTokenOut - _initialBalanceTokenOut) == amount,
            "Invalid wrapper contract"
        );
        // send ETH to the user
        payable(receiverAddress).transfer(amount);
    }
    
    emit SocketSwapTokens(
        fromToken,
        toToken,
        amount,
        amount,
        Identifier,
        receiverAddress,
        metadata
    );
    return amount;
}

4.2 正常功能逻辑

该函数设计用于ETH与WETH的转换,主要功能路径:

  1. ETH转WETH:

    • 检查fromToken是否为原生代币地址
    • 记录初始WETH余额
    • 执行WETH合约调用,转入ETH
    • 验证WETH余额增加量等于转入的ETH数量
    • 将WETH转给接收者
  2. WETH转ETH:

    • 记录初始ETH余额
    • 从调用者转移WETH到合约
    • 执行WETH合约调用,提取ETH
    • 验证ETH余额增加量等于提取的WETH数量
    • 将ETH转给接收者

4.3 漏洞点分析

漏洞存在于以下关键点:

  1. amount参数为0时的验证绕过:

    • amount为0时,(_finalBalanceTokenOut - _initialBalanceTokenOut) == amount恒成立
    • 这使得余额验证检查被绕过
  2. swapExtraData参数可控:

    • 攻击者可以完全控制swapExtraData参数
    • 通过构造恶意的swapExtraData,可以调用任意代币的transferFrom函数
  3. fromToken参数未严格验证:

    • 函数没有严格限制fromToken必须为WETH地址
    • 允许传入任意代币地址

5. 攻击流程详解

  1. 攻击准备:

    • 攻击者创建2个攻击合约
    • 识别出performAction函数的漏洞
  2. 攻击执行:

    • 调用performAction函数,设置amount为0
    • 设置fromToken为受害者已授权的代币地址(如USDC)
    • 构造swapExtraData为调用该代币transferFrom函数的数据
    • 由于amount为0,余额验证检查被绕过
    • 恶意transferFrom调用被执行,转移受害者授权的代币
  3. 资金转移:

    • 攻击者将获取的USDC、USDT、WETH、WBTC、DAI、MATIC等代币全部转换为ETH
    • 最终获利约330万美元

6. 漏洞修复建议

  1. 严格验证输入参数:

    require(amount > 0, "Amount must be greater than zero");
    require(fromToken == NATIVE_TOKEN_ADDRESS || fromToken == WETH_ADDRESS, "Invalid token");
    require(toToken == NATIVE_TOKEN_ADDRESS || toToken == WETH_ADDRESS, "Invalid token");
    
  2. 限制swapExtraData的使用:

    • swapExtraData进行严格格式验证
    • 或完全移除该参数,改为固定调用已知安全的函数
  3. 添加权限控制:

    modifier onlyAuthorized() {
        require(msg.sender == authorizedRouter, "Unauthorized");
        _;
    }
    
  4. 改进余额验证逻辑:

    • 即使amount为0也应进行严格验证
    • 可以考虑添加最小交换量限制

7. 安全开发最佳实践

  1. 输入验证:

    • 对所有外部输入进行严格验证
    • 特别是涉及资金操作的参数
  2. 边界条件测试:

    • 特别关注0值、最大值等边界条件
    • 编写全面的单元测试覆盖所有边界情况
  3. 最小权限原则:

    • 合约函数应遵循最小权限原则
    • 避免过度灵活的接口设计
  4. 代码审计:

    • 在部署前进行专业的安全审计
    • 特别是涉及资金操作的合约

8. 总结

Socket Gateway漏洞展示了智能合约开发中几个关键的安全问题:

  • 边界条件处理不足
  • 过度灵活的接口设计
  • 输入验证不严格
  • 权限控制缺失

开发者应从该事件中吸取教训,在设计和实现智能合约时遵循安全最佳实践,特别是在处理代币转移等敏感操作时。

Socket Gateway 代币交换逻辑漏洞分析报告 1. 事件概述 2024年1月17日,Socket Gateway智能合约由于 performAction 函数中存在逻辑漏洞,导致约330万美元的损失。攻击者利用该漏洞转移了用户的USDC、USDT、WETH、WBTC、DAI和MATIC等代币,并将其转换为ETH获利。 2. 关键地址信息 攻击者地址 : 0x50DF5a2217588772471B84aDBbe4194A2Ed39066 被攻击合约地址 : 0x3a23F943181408EAC424116Af7b7790c94Cb97a5 漏洞合约地址 : 0xCC5fDA5e3cA925bd0bb428C8b2669496eE43067e 攻击交易示例 : 0xc6c3331fa8c2d30e1ef208424c08c039a89e510df2fb6ae31e5aa40722e28fd6 攻击合约地址 : 0xf2D5951bB0A4d14BdcC37b66f919f9A1009C05d1 3. 漏洞背景 Socket Gateway的Admin在1月13日执行了 addRoute 函数添加了新的routeAddress。新部署的合约中的 performAction 函数存在逻辑错误,该函数原本设计用于ETH与WETH的代币交换。 4. 漏洞代码分析 4.1 漏洞函数代码 4.2 正常功能逻辑 该函数设计用于ETH与WETH的转换,主要功能路径: ETH转WETH : 检查 fromToken 是否为原生代币地址 记录初始WETH余额 执行WETH合约调用,转入ETH 验证WETH余额增加量等于转入的ETH数量 将WETH转给接收者 WETH转ETH : 记录初始ETH余额 从调用者转移WETH到合约 执行WETH合约调用,提取ETH 验证ETH余额增加量等于提取的WETH数量 将ETH转给接收者 4.3 漏洞点分析 漏洞存在于以下关键点: amount参数为0时的验证绕过 : 当 amount 为0时, (_finalBalanceTokenOut - _initialBalanceTokenOut) == amount 恒成立 这使得余额验证检查被绕过 swapExtraData参数可控 : 攻击者可以完全控制 swapExtraData 参数 通过构造恶意的 swapExtraData ,可以调用任意代币的 transferFrom 函数 fromToken参数未严格验证 : 函数没有严格限制 fromToken 必须为WETH地址 允许传入任意代币地址 5. 攻击流程详解 攻击准备 : 攻击者创建2个攻击合约 识别出 performAction 函数的漏洞 攻击执行 : 调用 performAction 函数,设置 amount 为0 设置 fromToken 为受害者已授权的代币地址(如USDC) 构造 swapExtraData 为调用该代币 transferFrom 函数的数据 由于 amount 为0,余额验证检查被绕过 恶意 transferFrom 调用被执行,转移受害者授权的代币 资金转移 : 攻击者将获取的USDC、USDT、WETH、WBTC、DAI、MATIC等代币全部转换为ETH 最终获利约330万美元 6. 漏洞修复建议 严格验证输入参数 : 限制swapExtraData的使用 : 对 swapExtraData 进行严格格式验证 或完全移除该参数,改为固定调用已知安全的函数 添加权限控制 : 改进余额验证逻辑 : 即使 amount 为0也应进行严格验证 可以考虑添加最小交换量限制 7. 安全开发最佳实践 输入验证 : 对所有外部输入进行严格验证 特别是涉及资金操作的参数 边界条件测试 : 特别关注0值、最大值等边界条件 编写全面的单元测试覆盖所有边界情况 最小权限原则 : 合约函数应遵循最小权限原则 避免过度灵活的接口设计 代码审计 : 在部署前进行专业的安全审计 特别是涉及资金操作的合约 8. 总结 Socket Gateway漏洞展示了智能合约开发中几个关键的安全问题: 边界条件处理不足 过度灵活的接口设计 输入验证不严格 权限控制缺失 开发者应从该事件中吸取教训,在设计和实现智能合约时遵循安全最佳实践,特别是在处理代币转移等敏感操作时。