合约代码:
QBridge:https://etherscan.io/address/0x99309d2e7265528dC7C3067004cC4A90d37b7CC3#code
QBridgeHandler:https://etherscan.io/address/0x99309d2e7265528dC7C3067004cC4A90d37b7CC3#code
攻击交易:
https://etherscan.io/tx/0x478d83f2ad909c64a9a3d807b3d8399bb67a997f9721fc5580ae2c51fab92acf
设置0地址白名单交易:
https://etherscan.io/tx/0xe3da555d506638bd7b697c0bdf7920be8defc9a175cd35bf72fb10bc77167b66
在合约QBridge中有函数deposit
和depositETH
代码功能几乎相同,分别调用handler的deposit
和depositETH
,
但handler中函数deposit
function deposit(bytes32 resourceID, address depositer, bytes calldata data) external override onlyBridge {
uint option;
uint amount;
(option, amount) = abi.decode(data, (uint, uint));
address tokenAddress = resourceIDToTokenContractAddress[resourceID];
require(contractWhitelist[tokenAddress], "provided tokenAddress is not whitelisted");
if (burnList[tokenAddress]) {
require(amount >= withdrawalFees[resourceID], "less than withdrawal fee");
QBridgeToken(tokenAddress).burnFrom(depositer, amount);
} else {
require(amount >= minAmounts[resourceID][option], "less than minimum amount");
tokenAddress.safeTransferFrom(depositer, address(this), amount);
}
}
未校验tokenaddress地址是否为合约(同时将地址0x000000000…00设置为默认eth地址),导致在调用tokenAddress.safeTransferFrom(depositer, address(this), amount);
时,由于 tokenAddress 地址为 0 地址,而 call 调用无 code size 的地址时其执行结果都会为 true 。最后触发了Deposit事件,跨链铸造了大量qXETH