链资讯 链资讯
Ctrl+D收藏链资讯
首页 > USDC > 正文

OMM:智能合约安全审计入门篇 —— 抢跑_HASH

作者:

时间:

背景概述

在上篇文章中我们了解了合约中隐藏的恶意代码,本次我们来了解一个非常常见的攻击手法——抢跑。

前置知识

提到抢跑,大家第一时间想到的一定是田径比赛,在田径运动中各个选手的体能素质几乎相同,起步越早的人得到第一名的概率越大。那么在以太坊中是如何抢跑的呢?

想了解抢跑攻击必须先了解以太坊的交易流程,我们通过下面这个发送交易的流程图来了解以太坊上一笔交易发出后经历的流程:

可以看到图中一笔交易从签名到被打包一共会经历7个阶段:

1.使用私钥对交易内容签名;

2.选择GasPrice;

3.发送签名后的交易;

4.交易在各个节点之间广播;

5.交易进入交易池;

6.矿工取出GasPrice高的交易;

7.矿工打包交易并出块。

交易送出之后会被丢进交易池里,等待被矿工打包。矿工从交易池中取出交易进行打包与出块。根据Eherscan?的数据,目前区块的Gas限制在3000万左右这是一个动态调整的值。若以一笔基础交易21,000Gas来计算,则目前一个以太坊区块可以容纳约1428笔交易。因此当交易池里的交易量大时,会有许多交易没办法即时被打包而滞留在池子中等待。这里就衍生出了一个问题,交易池中有那么多笔交易,矿工先打包谁的交易呢?

矿工节点可以自行设置参数,不过大多数矿工都是按照手续费的多少排序。手续费高的会被优先打包出块,手续费低的则需要等前面手续费高的交易全部被打包完才能被打包。当然进入交易池中的交易是源源不断的,不管交易进入交易池时间的先后,手续费高的永远会被优先打包,手续费过低的可能永远都不会被打包。

那么手续费是怎么来的呢?

我们先看以太坊手续费计算公式:

神话起源CEO谈毅:以太坊GAS和速度以及智能合约是未来突破的方向:金色财经现场报道,在8月8日由金色财经主办的金色沙龙活动中,神话起源CEO谈毅在主题《哪些Web3叙事将引领下轮牛市》的圆桌会议中表示,以太坊有三个大家可以关注的点,以及存在的核心价值。一个是GAS,一个是速度,一个是智能合约,这是以太坊做这么大的核心。换句话说,未来的突破也在这三个方向上。

以GAS和速度为例,一个是2.0的升级,今年下半年能不能如期推出,推出以后的效果,能不能像人们预期的那样。这有可能是一下子给加密资产带来一个新的台阶。做L2的团队,也在L2层面上解决这个问题,一个是速度,一个是GAS。第三个是智能合约,以太坊就是行业标准。它从NFT开始,ERC-721以后,还有EIP-1159,今年好像也有新的智能合约的协议会提交出来做审核。所以如果从这三个点上突破的话,以太坊的价值和生态能进一步的扩大和提升。尤其是智能合约。今年可以看到有很多创新想法,随着NFT往下发展,在用新的智能合约做,这都是以太坊可以关注的点。

此外,他还表示,游戏资产能天然跟区块链做融合,既符合有非常大的资产价格波动性,又是可触及的。通过可触及的方式,让更多的圈外人进来。[2023/8/8 21:32:31]

TxFee=GasUsed*?GasPrice

其中GasUsed是由系统计算得出的,GasPrice是可以自定义的,所以最终手续费的多少取决于GasPrice设置的多少。

举个例子:

例如GasPrice设置为10GWEI,GasUsed?为21,000。因此,根据手续费计算公式可以算出手续费为:

10GWEI*21,000=0.00021Ether

在合约中我们常见到Call函数会设置GasLimit,下面我们来看看它是什么东西:

GasLimit可以从字面意思理解,就是Gas限制的意思,设置它是为了表示你愿意花多少数量的Gas在这笔交易上。当交易涉及复杂的合约交互时,不太确定实际的GasUsed,可以设置GasLimit,被打包时只会收取实际GasUsed作为手续费,多给的Gas会退返回来,当然如果实际操作中GasUsed>GasLimit就会发生Outofgas,造成交易回滚。

Astar宣布其WASM智能合约赏金提案已获得批准:金色财经报道,Astar表示,其WASM智能合约赏金提案已获得批准,团队联盟将鼓励、促进、采用和开发Polkadot平行链上的Web Assembly智能合约。[2023/3/5 12:42:44]

当然,在实际交易中选择一个合适的GasPrice也是有讲究的,我们可以在ETHGASSTATION上看到实时的GasPrice对应的打包速度:

由上图可见,当前最快的打包速度对应的GasPrice为2,我们只需要在发送交易时将GasPrice设置为>=2的值就可以被尽快打包。

好了,到这里相信大家已经可以大致猜出抢跑的攻击方式了,就是在发送交易时将GasPrice调高从而被矿工优先打包。下面我们还是通过一个合约代码来带大家了解抢跑是如何完成攻击的。

合约示例

//?SPDX-License-Identifier:?MITpragmasolidity^0.8.17;contractFindThisHash{??bytes32publicconstanthash=????0x564ccaf7594d66b1eaaea24fe01f0585bf52ee70852af4eac0cc4b04711cd0e2;??constructor()payable{}??functionsolve(stringmemorysolution)public{????require(hash==keccak256(abi.encodePacked(solution)),"Incorrectanswer");????(boolsent,)=msg.sender.call{value:10ether}("");????require(sent,"FailedtosendEther");??}}

攻击分析

通过合约代码可以看到?FindThisHash?合约的部署者给出了一个哈希值,任何人都可以通过solve()?提交答案,只要solution的哈希值与部署者的哈希值相同就可以得到10个以太的奖励。我们这里排除部署者自己拿取奖励的可能。

元界DNA开发团队正在部署自定义智能合约:据元界官方推特消息,元界技术开发团队正在Substrate平台上实施智能合约。目前,开发团队已经确定并正在测试可行的技术解决方案,以部署自定义智能合约。与此前的所有重大技术更新一样,元界DNA始终以终端用户的体验为先,并致力于建立一个对用户安全、友好、流畅的公链项目。[2020/12/15 15:14:19]

我们还是请出老朋友Eve看看他是如何使用抢跑攻击拿走本该属于Bob的奖励的:

1.Alice使用10Ether部署FindThisHash合约;

2.Bob找到哈希值为目标哈希值的正确字符串;

3.Bob调用solve("Ethereum")并将Gas价格设置为15Gwei;

4.Eve正在监控交易池,等待有人提交正确的答案;

5.Eve看到Bob发送的交易,设置比Bob更高的GasPrice,调用solve("Ethereum");

6.Eve的交易先于Bob的交易被矿工打包;

7.Eve赢得了10个以太币的奖励。

这里Eve的一系列操作就是标准的抢跑攻击,我们这里就可以给以太坊中的抢跑下一个定义:抢跑就是通过设置更高的GasPrice来影响交易被打包的顺序,从而完成攻击。

那么这类攻击该如何避免呢?

修复建议

在编写合约时可以使用Commit-Reveal方案:

https://medium.com/swlh/exploring-commit-reveal-schemes-on-ethereum-c4ff5a777db8

SoliditybyExample中提供了下面这段修复代码,我们来看看它是否可以完美地防御抢跑攻击。

//SPDX-License-Identifier:MITpragmasolidity^0.8.17;import"github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.5/contracts/utils/Strings.sol";contractSecuredFindThisHash{??//Structisusedtostorethecommitdetails??structCommit{????bytes32solutionHash;????uintcommitTime;????boolrevealed;??}??//Thehashthatisneededtobesolved??bytes32publichash=????0x564ccaf7594d66b1eaaea24fe01f0585bf52ee70852af4eac0cc4b04711cd0e2;??//Addressofthewinner??addresspublicwinner;??//Pricetoberewarded??uintpublicreward;??//Statusofgame??boolpublicended;??//Mappingtostorethecommitdetailswithaddress??mapping(address=>Commit)commits;??//Modifiertocheckifthegameisactive??modifiergameActive(){????require(!ended,"Alreadyended");????_;??}??constructor()payable{????reward=msg.value;??}??/*???Commitfunctiontostorethehashcalculatedusingkeccak256(addressinlowercase+solution+secret).???Userscanonlycommitonceandifthegameisactive.??*/??functioncommitSolution(bytes32_solutionHash)publicgameActive{????Commitstoragecommit=commits;????require(commit.commitTime==0,"Alreadycommitted");????commit.solutionHash=_solutionHash;????commit.commitTime=block.timestamp;????commit.revealed=false;??}??/*????Functiontogetthecommitdetails.Itreturnsatupleof(solutionHash,commitTime,revealStatus);?????UserscangetsolutiononlyifthegameisactiveandtheyhavecommittedasolutionHash??*/??functiongetMySolution()publicviewgameActivereturns(bytes32,uint,bool){????Commitstoragecommit=commits;????require(commit.commitTime!=0,"Notcommittedyet");????return(commit.solutionHash,commit.commitTime,commit.revealed);??}??/*????Functiontorevealthecommitandgetthereward.????UserscangetrevealsolutiononlyifthegameisactiveandtheyhavecommittedasolutionHashbeforethisblockandnotrevealedyet.????Itgeneratesankeccak256(msg.sender+solution+secret)andchecksitwiththepreviouslycommitedhash.?????Frontrunnerswillnotbeabletopassthischecksincethemsg.senderisdifferent.????Thentheactualsolutionischeckedusingkeccak256(solution),ifthesolutionmatches,thewinnerisdeclared,????thegameisendedandtherewardamountissenttothewinner.??*/??functionrevealSolution(????stringmemory_solution,????stringmemory_secret)publicgameActive{????Commitstoragecommit=commits;????require(commit.commitTime!=0,"Notcommittedyet");????require(commit.commitTime<block.timestamp,"Cannotrevealinthesameblock");????require(!commit.revealed,"Alreadycommitedandrevealed");????bytes32solutionHash=keccak256(??????abi.encodePacked(Strings.toHexString(msg.sender),_solution,_secret)????);????require(solutionHash==commit.solutionHash,"Hashdoesn'tmatch");????require(keccak256(abi.encodePacked(_solution))==hash,"Incorrectanswer");????winner=msg.sender;????ended=true;????(boolsent,)=payable(msg.sender).call{value:reward}("");????if(!sent){??????winner=address(0);??????ended=false;??????revert("Failedtosendether.");????}??}}

Cardano创始人回应BM的质疑:Cardano不是DPoS 智能合约和本地资产将在今年推出:8月1日,网友@crypto_spaced发推称Cardano是DPoS,且EOS创始人Daniel Larimer(BM)在其很早前就称Cardano是DPoS。Cardano创始人Charles Hoskinson回复称:“我们不是DPoS。Ouroboros是一种全新的协议。”“BM说谎了,他还说我们的协议不起作用。他称这是一件800磅重、挡不住子弹的防弹背心。我很抱歉,不管你信不信他,他说谎了,他把我们的协议说成DPoS是大错特错。”8月3日,BM回复Hoskinson称:“你的协议不适用于货币以外的应用程序,对于大多数DeFi而言,确认等待时间太长,并且完全不适用于大多数用例。”Hoskinson对此表示:“智能合约和本地资产将在今年推出,我们的延迟比以太坊的更低。占主导地位的DeFi平台hydra将把它带到次秒级。引用中本聪的话:对不起,我没有时间向你解释。”[2020/8/3]

首先可以看到修复代码中使用了结构体Commit记录玩家提交的信息,其中:

commit.solutionHash=_solutionHash=keccak256

commit.commitTime=block.timestamp

commit.revealed=false

下面我们看这个合约是如何运作的:

1.Alice使用十个以太部署SecuredFindThisHash合约;

2.Bob找到哈希值为目标哈希值的正确字符串;

3.Bob计算solutionHash=keccak256(Bob’sAddress+“Ethereum”+Bob’ssecret);

4.Bob调用commitSolution(_solutionHash),提交刚刚算出的solutionHash;

5.Bob在下个区块调用revealSolution("Ethereum",Bob'ssecret)函数,传入答案和自己设置的密码,领取奖励。

声音 | 央行穆长春:央行数字货币会加载有利于货币职能的智能合约:中国人民银行支付结算司副司长穆长春在中国金融四十人论坛上表示,中国央行数字货币是可以加载智能合约的。在此需要强调的一点是,央行数字货币依然是具有无限法偿特性的货币,它是对M0的替代。它所具有的货币职能(交易媒介、价值储藏、计账单位)决定其如果加载了超出其货币职能的智能合约,就会使其退化成有价票证,降低可使用程度,会对人民币国际化产生不利影响,因此,我们会加载有利于货币职能的智能合约,但对于超过货币职能的智能合约还是会保持比较审慎的态度。[2019/8/10]

这里我们看下这个合约是如何避免抢跑的,首先在第四步的时候,Bob提交的是这三个值的哈希,所以没有人知道Bob提交的内容到底是什么。这一步还记录了提交的区块时间并且在第五步的revealSolution()?中就先检查了区块时间,这是为了防止在同一个区块开奖被抢跑,因为调用revealSolution()?时需要传入明文答案。最后使用Bob输入的答案和密码验证与之前提交的solutionHash哈希是否匹配,这一步是为了防止有人不走commitSolution()?直接去调用revealSolution()。验证成功后,检查答案是否正确,最后发放奖励。

所以这个合约真的完美地防止了Eve抄答案吗?

Ofcoursenot!

咋回事呢?我们看到在revealSolution()?中仅限制了commit.commitTime<block.timestamp?,所以假设Bob在第一个区块提交了答案,在第二个区块立马调用revealSolution("Ethereum",Bob'ssecret)?并设置GasPrice=15Gwei?Eve,通过监控交易池拿到答案,拿到答案后他立即设置GasPrice=100Gwei,在第二个区块中调用commitSolution()?,提交答案并构造多笔高GasPrice的交易,将第二个区块填满,从而将Bob提交的交易挤到第三个区块中。在第三个区块中以100Gwei的GasPrice调用revealSolution("Ethereum",Eve'ssecret)?,得到奖励。

那么问题来了,如何才能有效地防止此类攻击呢?

很简单,只需要设置uint256revealSpan?值并在commitSolution()中检查?require(commit.commitTime+revealSpan>=block.timestamp,"Cannotcommitinthisblock");,这样就可以防止Eve抄答案的情况。但是在开奖的时候,还是无法防止提交过答案的人抢先领奖。

另外还有一点,本着代码严谨性,修复代码中的revealSolution()?函数执行完后并没有将commit.revealed?设为True,虽然这并不会影响什么,但是在编写代码的时候还是建议养成良好的编码习惯,执行完函数逻辑后将开关设置成正确的状态。

标签:OMMUTIASHHASH3COMMAS币ADAB SolutionsPepe Cashhashcoin

USDC热门资讯
MEV:解析MEV-Burn:下一个以太坊重大升级_BURN

作者:DonovanChoy,Bankless翻译:金色财经xiaozou2021年8月以太坊主网实施EIP-1559,标志着以太坊网络第一次开始burnETH.

NFT:NFT 和 AI 新兴技术共赴盛宴,一场前所未有的英国加冕皇室体验_ONES

随着英国隆重迎来国王查理三世时代,电视报道将主要集中在游行盛典和皇冠珠宝上。但在全国各地,庆祝加冕典礼的方式不再过时,而是更加数字化,不乏有创新者使用区块链和限量版NFT等新兴技术来大肆庆祝.

MIT:23天10亿美元市值 PEPE上升期结束了吗_COM

关键洞察 PEPE已成为加密货币历史上增长最快的ERC-20代币,在短短23天内获得了10亿美元的市值和107,000个持有者;?PEPE引发了Meme币的复兴.

COM:PEPE再掀投机热潮 下一个Meme Coin是什么?_OMMI价格

购买?MemeCoin?能“致富”吗?近期的?PEPE?一直在话题热榜上,改变了“不温不火”的市场现状,重新点燃了用户心中靠?Crypto?一夜暴富的梦想.

NLA:Bankless:EigenLayer测试网使用教程_BRC

以太坊质押场景中的下一件大事是EigenLayer,这是一种新的「再质押」协议,有望为以太坊的质押者提供大量新的盈利机会.

LAYER:为什么推特KOL都在BRC赚钱 我一冲就亏?_BRC

近日的市场热度令人焦虑,但真的这么多人在BRC-20上赚钱了吗?纵览推特,众多KOL号称在BRC-20大赚了一笔,纷纷分享心得,目前,领涨的ORDI?单价已突破27?美元.