预计阅读时间:10min
近来市场上存在一些因“一键式指导”部署而受骗的项目,文中对其中出现的安全漏洞进行复现,旨在避免更多因类似漏洞而遭受损失的项目出现。
查看整个教程指导书后发现,其给出代码中存在不少程序开发人员留下的“后门”漏洞,该问题可导致整个项目代币在对应的Uniswap资金池中产生异常的兑换。下面跟着笔者一探究竟,这种“一键式指导”如何一步步诱导相对技术小白的项目运营管理人员以及其用户落入陷阱。
附上“指导书”链接:https://note.youdao.com/ynoteshare1/index.html?id=7c0336d0208b438802e920efa5396d5e&type=note
后门,本意是指一座建筑背面开设的门,通常比较隐蔽,为进出建筑的人提供方便和隐蔽。在信息安全领域,后门是指绕过安全控制而获取对程序或系统访问权的方法。后门的最主要目的就是方便以后再次秘密进入或者控制系统。
后门在区块链智能合约中最典型的实现方法就是在某些限定权限的函数中较为隐蔽的写入指定代码能够使指定地址具有对应函数操作权限,从而实现一些数字货币操作,例如转账,铸币,销毁等。
开门见山,指导书上来就显示了其“及其专业”的部署教学,以及给出了对应的源码(这里笔者提醒大家切勿相信或使用任何不可信人员提供的智能合约代码进行项目运营或个人投资),根据“指导书”顺利进行部署发行项目代币。
在项目部署成功后开始引诱项目方通过Uniswap添加流动性资金池,到这里为止,一切看起来都很正常,在项目管理人员添加完流动性后,我们回到这份源码本身来分析这份指导书中充满的重重陷阱。
如下图所示,整个源码框架其实很简单,主要包含ERC20、ERC20Detailed和UniswapExchange三个合约(对应下图标识1-3),其中而前两个合约功能未完全实现且第三个合约与前两个并无继承关系,所以该合约文件中实际功能全部来自于UniswapExchange合约。
UniswapExchange合约中实现了与普通ERC20代币接口完全一致的函数功能,但是与普通代币转账功能不同的是,主要功能函数transfer、transferFrom以及approve函数均添加了修饰符payable来修饰函数。
payable 方法是让 Solidity 和以太坊变得如此酷的一部分,它是一种可以接收以太的特殊函数,即payable修饰符可以使得该函数在交易的时候传入ETH,这就给后面的第一个陷阱埋下了隐患。
该陷进主要针对该合约发行代币用户,其在转账过程中容易发生误操作将除去gas费用外的ETH转入合约中,该部分ETH在用户看来是无法恢复的,但是合约中存在一个delegate函数(如下图所示),通过delegatecall函数可将合约中ETH转入指定地址。
复现测试合约地址:https://ropsten.etherscan.io/address/0x4358f98d9d74b2b6538bdf1e3665ad9a35f21521#code
如下图所示,用户在进行普通代币转账或者授权的时候可以将ETH转入合约,尤其是授权操作,在去中心化交易所中均会涉及授权操作,一旦该去中心化交易所前端作恶且用户粗心确认交易就会落入该陷进。
如下图所示,该合约中已转入1 ETH。
现在我们来复现如何将合约中ETH转入任意指定地址:
首先部署一个攻击(复现)合约,源码如下所示,附链接:https://ropsten.etherscan.io/address/0x69edeca1b716be189c4e1749e838bf2333223fc3#code
由于在该合约案例中,合约owner权限无法变更且此处并没有留“后门”,所以该函数仅可由owner地址调用,此案例合约中转入的ETH受益方为项目部署人员。
回顾图4中该后门源码,其关键点在于使用了低级调用函数delegatecall,通俗来讲,即在本合约中执行外部合约代码,其它信息则使用当前合约环境变量(如存储,余额等等)
。
接下来进行复现调用,将BDR合约中的ETH转入复现合约中指定地址,根据图示内容改进型如下调用:
交易成功,附上交易链接:https://ropsten.etherscan.io/tx/0xffc5b988cac94f5fb7ea81d62ce42e044ddb0b2944cc52a44ae2a56dbcff5116
查看原合约,其合约ETH余额被清空:
该陷阱主要由后门铸币产生,对应本案例,核心问题在如下几点。
首先,如下图所示,从函数命名开始迷惑,一般来说函数命名规则里“_functionName”形式一般为internal/private类型的函数。注意,此处函数修饰符为public,这不符合我们审计过程中对函数访问权限的要求;虽然该函数有函数调用权限,可是通过隐性编码的方式额外将一个指定地址赋予了调用权限。
该隐性编码实际原理即将普通的用户地址转换为Hex(十六进制数值)格式,再在合约代码中通过address类型强转为地址,这样在代码层面看起来像是不存在任何外部地址的。附上隐性编码复现合约,其中地址为本案例中实际后门权限所有地址:https://ropsten.etherscan.io/address/0xb5a7d858656c32da3036433f1249be4dd8e8eff0#code
其次通过后门权限地址为自己进行“铸币”,可以超过原先代币总量进行铸币,这一步操作是在Uniswap资金池中恶意兑换的关键。关于本案,其实槽点多多,本身铸币逻辑不合理,其次项目方部署者(owner)其实也是可以通过该操作进行“内部作案”的,笔者还是推荐各位使用安全的代码,多多注意。
将后门权限修改为笔者地址后重新部署“指导书”合约,附上地址:https://ropsten.etherscan.io/address/0x48082341fcc7dea23b1ef63a45099ad0cc43b7c8#code
铸币操作结束后,代币余额查询如下,该笔交易链接如下:https://ropsten.etherscan.io/tx/0xc8f82de418b8730e9e9dfe2d25be2e4e9602a6ef80c83c2bc5aa952115a611e4
根据“指导书”进行一系列在Uniswap上的“送钱”操作:
B.查询流动性代币合约https://ropsten.etherscan.io/address/0xf62e032648b743fae6a6b285f8e906fcbc33bf82
C. 按照“指导书”中合约对应的“功能设置(其中描述与代码功能并不匹配)”对合约兑换进行初始化结束后在Uniswap使用后门地址进行恶意兑换,将资金池中的价值货币兑换至自己的地址
尝试通过浏览器通过合约直接调用兑换功能(UniswapV2Router02合约中swapExactTokensForETH函数)来实现一次性转出。
输入兑换参数,分别代表兑换数量,提取数量,pair地址(BDR2/WETH),后门获利地址,大于调用时间的时间戳,进行调用。
调用前,后门地址余额如下
进行授权
调用成功,交易链接:https://ropsten.etherscan.io/tx/0xdfa6cef1352117c4a0afbe677e9948c333169818d6d4a7ce04ac8b0be78b5055
查询后门地址余额,该笔非法兑换交易到账,项目方投入资金池的ETH最终因为“指导书”中的代码以及一步步的“教学”,落入了后门地址的腰包。
到此可以看到,本案例中“一键式指导”项目因为代码安全漏洞以及项目运营方技术缺陷,导致使用该代码进行项目运营的相关人员遭受了损失。
智能合约编写正确性以及权限控制尤为重要,稍有不慎,隐藏在合约中的后门漏洞就会造成一定的损失。警惕一切外来智能合约代码,不轻易在安全性未知的智能合约代码项目进行项目运营及个人投资。