【漏洞分析】DoughFina 攻击事件分析:不做任何参数检查的去杠杆合约
背景介绍
2024 年 7 月 12 日,DoughFina 协议遭受了黑客攻击,造成本次攻击的主要原因是 ConnectorDeleverageParaswap 合约没有对输入参数进行检查,且该合约为 DSA 合约的 owner。攻击者可以构造恶意参数窃取 DSA 合约的资金。
相关合约
- DSA(被攻击地址):0x534a
在 AAVE V3 上质押了 596 WETH,借出了 938566 USDC - 攻击合约:0x11a8
- ConnectorDeleverageParaswap:0x9f54e8eaa9658316bb8006e03fff1cb191aafbe6
通过闪电贷协助 DSA 降低在 AAVE V3 上的杠杆。
攻击交易分析
这个章节我们先尝试从 trace 来定位漏洞的位置。
通过对这笔交易进行一个大概的观察,如下图所示,攻击者在发起攻击之前,先利用闪电贷的资金帮 0x534a 归还了他的借款 938566 USDC,其他部分都是常规的操作,其中需要深入调查的就是 0x11a8 调用 ConnectorDeleverageParaswap.flashloanReq 函数的过程。

ConnectorDeleverageParaswap.flashloanReq 函数

我们看到在 ConnectorDeleverageParaswap.flashloanReq 函数中,会调用 POOL.flashLoan
POOL.flashLoan 执行一个常规的闪电贷流程
- ConnectorDeleverageParaswap 合约从闪电贷获取 5 USDC
- 调用 ConnectorDeleverageParaswap.executeOperation 函数
- 归还 5.025 USDC
- handleRepayment

继续跟进到 ConnectorDeleverageParaswap.executeOperation 函数,可以看到它对传入的参数进行解析后直接调用 deloopInOneOrMultipleTransactions 函数

对 deloopInOneOrMultipleTransactions 函数进行分析
function deloopInOneOrMultipleTransactions(bool opt, address _dsaAddress, address[] memory assets, uint256[] memory amounts, uint256[] memory premiums, address[] memory collateralTokens, uint256[] memory collateralAmounts, bytes[] memory multiTokenSwapData) private {
// Repay all flashloan assets or withdraw all collaterals
// 使用闪电贷获得的资金来偿还用户在 Aave 上的债务。
repayAllDebtAssetsWithFlashLoan(opt, _dsaAddress, assets, amounts);
// Extract all collaterals
// 从用户的 DSA 中提取指定数量的抵押品。
extractAllCollaterals(_dsaAddress, collateralTokens, collateralAmounts);
// Deloop all collaterals
// 使用 Paraswap 将提取的抵押品换成债务代币
deloopAllCollaterals(multiTokenSwapData);
// Repay all flashloan assets or withdraw all collaterals
// 偿还闪电贷,然后将剩余的资金存回 Aave 或转移到金库
repayFlashloansAndTransferToTreasury(opt, _dsaAddress, assets, amounts, premiums);
}
不过在查看 ConnectorDeleverageParaswap.executeOperation 函数的执行 trace 时,发现 Phalcon 把调用的四个函数混在一起了不好分辨。

根据转移的金额确定攻击发生的位置,猜测这笔 WETH 的转账与漏洞的利用有关。

所以通过单步调试的方式来检查发生了什么。
执行到 ConnectorDeleverageParaswap.deloopAllCollaterals 函数中时,对传入的 multiTokenSwapData 参数进行解析,得到对应的参数: flashloanVars.srcToken, flashloanVars.destToken, flashloanVars.srcAmount, flashloanVars.destAmount, flashloanVars.paraSwapContract, flashloanVars.tokenTransferProxy, flashloanVars.paraswapCallData
其中 paraSwapContract(out4)对应的地址为 WETH 的合约地址(0xc02a),而不是进行 swap 的合约地址。

当执行到 paraSwapContract.call 部分的函数时,由于 paraSwapContract 的地址已被替换为 WETH9 的地址,且 paraswapCallData 为攻击者构造的转账 calldata,所以实际执行的是 WETH 的转账操作
function deloopAllCollaterals(bytes[] memory multiTokenSwapData) private {
FlashloanVars memory flashloanVars;
for (uint i = 0; i < multiTokenSwapData.length;) {
// Deloop
(flashloanVars.srcToken, flashloanVars.destToken, flashloanVars.srcAmount, flashloanVars.destAmount, flashloanVars.paraSwapContract, flashloanVars.tokenTransferProxy, flashloanVars.paraswapCallData) = _getParaswapData(multiTokenSwapData[i]);
// using ParaSwap
IERC20(flashloanVars.srcToken).safeIncreaseAllowance(flashloanVars.tokenTransferProxy, flashloanVars.srcAmount);
(flashloanVars.sent, ) = flashloanVars.paraSwapContract.call(flashloanVars.paraswapCallData);
if (!flashloanVars.sent) revert CustomError("ParaSwap deloop failed");
unchecked { i++; }
}
}
deloopInOneOrMultipleTransactions 函数分析
已经定位到了漏洞发生的位置,接下来就根据 trace 分析 deloopInOneOrMultipleTransactions 函数对四个函数的调用情况
repayAllDebtAssetsWithFlashLoan
替 0x11a8 账户归还 5 USDC 的借款

extractAllCollaterals
传入空数组,跳过这函数的逻辑

deloopAllCollaterals
由于没有进行参数检查,攻击者在这个函数中构造了两个恶意的调用来获利。

第一个 for 循环:调用 0x534a.executeAction 把 5 USDC 兑换成 596 WETH,并且 approve 给 ConnectorDeleverageParaswap 合约

第二个 for 循环:把 596 WETH 转移到攻击者控制的 0x11a8 地址

repayFlashloansAndTransferToTreasury
提供 0.9 USDC 给 0x11a8 的 AAVE 账户

攻击流程分析
本次攻击是围绕降低 0x11a8 账户在 AAVE V3 上的杠杆而展开的,由于这个函数没有对传入的参数进行检查,所以攻击者构造了恶意的 multiTokenSwapData 参数在 deloopAllCollaterals 函数中对 0x534a 的 AVVE 资金进行转移。
攻击者构造恶意的 data 参数,解析出恶意的 multiTokenSwapData 参数

恶意的 multiTokenSwapData 参数传入到 deloopAllCollaterals 函数中

恶意的 multiTokenSwapData 参数解析出恶意的 paraSwapContract 和 paraswapCallData,导致了任意执行。

后记
第一次分析这个类型的攻击事件,感觉攻击事件还是得多分析,多积累积累经验,扩展自己的视野。好好看好好学吧,之前对项目类型的接触和理解上都有很大的局限,还是需要多接触一下目前经典的、热门的项目有利于提高自己的水平,跟上市场的步伐。继续干呗,这事儿只能靠慢慢积累起来的。
【漏洞分析】DoughFina 攻击事件分析:不做任何参数检查的去杠杆合约的更多相关文章
- 孟加拉央行SWIFT攻击事件恶意木马分析(转)
第一章 分析概述 该恶意木马样本为运行于winodws平台上的PE文件(名称:evtdiag.exe).文件大小为64KB,编译时间是2016年2月5日. 经分析,该样本为定制的攻击SWIFT客户端程 ...
- 【漏洞复现】Paraluni 安全事件分析及复现
Paraluni 被黑分析 前言 Paraluni (平行宇宙)是新加坡 Parallel Universe 基金会发布的一个 基于币安智能链的 DeFi 项目,更多相关内容见此处.在 2022 年 ...
- 【漏洞分析】KaoyaSwap 安全事件分析
相关信息 KaoyaSwap 是 BSC 链上的一个自动做市商 AMM.然后,现在他们的官网 https://www.kaoyaswap.com/ 已经打不开了(如果我打开方式没错的话).所以就直接进 ...
- Log4shell漏洞研究及其挖矿案例分析
本文首发于云影实验室,为本人创作,现转载到个人博客,记录一下. 原文链接:https://mp.weixin.qq.com/s/O2xHr2OEHiga-qTnbWTxQg Apache Log4j是 ...
- ENode框架Conference案例分析系列之 - 事件溯源如何处理重构问题
前言 本文可能对大多数不太了解ENode的朋友来说,理解起来比较费劲,这篇文章主要讲思路,而不是一上来就讲结果.我写文章,总是希望能把自己的思考过程尽量能表达出来,能让大家知道每一个设计背后的思考的东 ...
- 从源码的角度分析ViewGruop的事件分发
从源码的角度分析ViewGruop的事件分发. 首先我们来探讨一下,什么是ViewGroup?它和普通的View有什么区别? 顾名思义,ViewGroup就是一组View的集合,它包含很多的子View ...
- OneAlert 入门(三)——事件分析
OneAlert 是国内首个 SaaS 模式的云告警平台,集成国内外主流监控/支撑系统,实现一个平台上集中处理所有 IT 事件,提升 IT 可靠性.有了 OneAlert,你可以更快更合理地为事件划分 ...
- 再谈DOMContentLoaded与渲染阻塞—分析html页面事件与资源加载
浏览器的多线程中,有的线程负责加载资源,有的线程负责执行脚本,有的线程负责渲染界面,有的线程负责轮询.监听用户事件. 这些线程,根据浏览器自身特点以及web标准等等,有的会被浏览器特意的阻塞.两个很明 ...
- [Abp 源码分析]九、事件总线
0.简介 事件总线就是订阅/发布模式的一种实现,本质上事件总线的存在是为了降低耦合而存在的. 从上图可以看到事件由发布者发布到事件总线处理器当中,然后经由事件总线处理器调用订阅者的处理方法,而发布者和 ...
- 007_ip统计及攻击ip分析
线上经常有被扫描的DDoS攻击事件,需要集合日志进行分析,这里有两种方法,分别是通过shell和python的方式. 一.shell '''<1>shell一句命令分析 http://bl ...
随机推荐
- java学习之旅(day.14)
可变字符串 StringBuffer:可变长字符串,运行效率慢,线程安全 StringBuilder:可变长字符串,运行效率快,线程不安全 package com.zhang.lei; //Strin ...
- 编译mmdetection3d时,无root权限下为虚拟环境单独创建CUDA版本
在跑一些深度学习代码的时候,如果需要使用mmdetection3d框架,下载的pytorch的cudatoolkit最好需要和本机的cuda版本是一样的,即输入nvcc -V命令后显示的版本一样. 但 ...
- WPF没修改代码出现InitializeComponent报错的解决办法
问题不在于我们做错了什么,之前还好好的,我们什么都没做,就报错了.这完全不是我们的问题. 我的建议是,直接做绝一点,删除obj和debug文件夹,让他自己重新生成一次
- Three加载3D模型贴图
Three加载3D模型贴图 准备阶段 3D模型 three 库文件 纹理图片 相关资料 官方开发文档: https://threejs.org/docs 官网编辑3D模型:https://threej ...
- 从零开始写 Docker(十五)---实现 mydocker run -e 支持环境变量传递
本文为从零开始写 Docker 系列第十五篇,实现 mydocker run -e, 支持在启动容器时指定环境变量,让容器内运行的程序可以使用外部传递的环境变量. 完整代码见:https://gith ...
- 基于Python的性能优化
一.多线程 在CPU不密集.IO密集的任务下,多线程可以一定程度的提升运行效率. import threading import time import requests def fetch_url( ...
- Fastapi获取其他第三方回调
flask.django获取第三方回调数据,可以用request.data直接获取全部参数.而很多同学不知道fastapi如何获取回调的全部参数,其实可以通过request.body(). 如: @p ...
- jquery加载页面时触发事件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- .NET桌面程序混合开发之三:WebView2与JS的深度应用
在 WebView2 控件中使用 JavaScript 根据需求自由扩展原生应用的能力.本文探讨如何在 WebView2 中使用 JavaScript,并列举如何使用高级 WebView2 特性和功能 ...
- 「C++」深度分析C++中i++与++i的区别
大家好,我是Charzie.在C++编程中,i++和++i是两个常见的自增运算符,用于将变量的值增加1(有时与i+=1效果一样).然而,虽然它们的功能看似相似,但在实际使用中却存在显著的区别.本博客将 ...