合约地址:
UniswapV2Router02(sashimi):https://etherscan.io/address/0xe4fe6a45f354e845f954cddee6084603cedb9410#code
UniswapV2Router02(uniswap):https://etherscan.io/address/0x7a250d5630b4cf539739df2c5dacb4c659f2488d#code
SashimiInvestment:https://etherscan.io/address/0x3f966fa1c0606e19047ed72068d2857677e07ef4#code
攻击交易:
https://etherscan.io/tx/0xd6a816cc291b24267c03c23c730a84a2699f32a7cf714c8cbe3e47321c76b08f
在UniswapV2Router02(sashimi)合约中函数swapExactTokensForETHSupportingFeeOnTransferTokens
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
)
external
virtual
override
ensure(deadline)
{
require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH');
address pair = UniswapV2Library.pairFor(factory, path[0], path[1]);
_transferIn(msg.sender,pair,path[0],amountIn);
uint balanceBefore = getTokenInPair(pair,WETH);
_swapSupportingFeeOnTransferTokens(path, address(this));
uint balanceAfter = getTokenInPair(pair,WETH);
uint amountOut = balanceBefore.sub(balanceAfter); ///获得pai的balance差
require(amountOut >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
_transferETH(to, amountOut);
}
再看UniswapV2Router02(uniswap)合约中函数swapExactTokensForETHSupportingFeeOnTransferTokens的源码
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
)
external
virtual
override
ensure(deadline)
{
require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH');
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn
);
_swapSupportingFeeOnTransferTokens(path, address(this));
uint amountOut = IERC20(WETH).balanceOf(address(this));
require(amountOut >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
IWETH(WETH).withdraw(amountOut);
TransferHelper.safeTransferETH(to, amountOut);
}
两者差异在sashimi合约中将所有pair计算后放入合约自身内计算,同时swapExactTokensForETHSupportingFeeOnTransferTokens只考虑了token:eth的单池转换,如果path为
token1:token2:eth时就会导致发送代币后无法接收到eth,同样如果路径为(代币以A,B,C代替,E代表Eth),A:E:B:C:E,就会导致代币A兑换的E流入E:B的池子;同时将A:E内池子的Eth差值传给攻击者,这时如果E:B为攻击者创建的池子,就可以撤掉池子再拿一份eth,
所以攻击者创建3个代币。
A:E中放入大量eth。其余池子仅放入少量eth。
后调用swapExactTokensForETHSupportingFeeOnTransferTokens 通过卖出大量A,将大量Eth传入E:B池中,B在传入B:C池…
同时因为sashimi合约中将所有pair计算后放入合约自身内计算,所以通过eth购买其他代币入usdt,dai等继续冲入eth到合约内,再提取eth,来榨取其他代币。
博客深入探讨了UniswapV2Router02合约在sashimi和uniswap两个版本中的差异,揭示了一个潜在的安全问题。攻击者可以利用sashimi合约中的逻辑错误,在多步交换过程中提取额外的ETH。该问题源于合约未正确处理多跳路径交换,导致资金可能流入攻击者控制的池子。通过创建特定的代币和路径,攻击者能够榨取其他代币价值并获取ETH。
7169

被折叠的 条评论
为什么被折叠?



