隐藏在众目睽睽之下:复盘etherscan的零日漏洞_合约招商_数字货币代理_海外数字货币招商代理_数字货币招商_元宇宙代理加盟

数字货币代理_海外数字货币招商代理_数字货币招商_元宇宙代理加盟
数字货币平台火爆招募数字货币合约代理

隐藏在众目睽睽之下:复盘etherscan的零日漏洞

更新时间:2021-11-12 19:12:01点击:68

data-v-3f0fa 3ab data-v-5f 989728“在以太网上发现0日(零日)的漏洞怎么办? 我决定做“弹珠”。 ' ——paradigm研究伙伴Samczsun )。

注:原文作者为samczsun。

我喜欢挑战假设。

我喜欢尝试做不可能的事,发现别人错过的东西,或者用他们从未见过的事来吓他们。 去年,我基于非常费解的Solidity漏洞向Paradigm CTF 2021写了挑战。 虽然公开了一种变体,但是我发现的漏洞实际上并没有被讨论过。 结果,想要挑战它的人大部分都被看起来不可能的性质所压倒。

几周前,我们在讨论关于Paradigm CTF 2022的计划。 当时,Georgios在推特上发布了一条难题推文。 我觉得在开始电话会议的同一天发表挑战很酷。 但是,这不仅仅是一个古老的挑战。 我想从这个世界得到什么。 有些没人看,有些超出了人们想象的极限。 希望利用0日(零日)的脆弱性,创建第一个以太坊CTF挑战赛。

如何制造0day(零日)漏洞

作为安全研究者,为了优化我们的时间,我会做一些基本的假设。 一个是,我们正在读的源代码确实产生了我们正在分析的合同。 当然,只有从可靠的地方(如Etherscan )读取源代码时,该假设才成立。 因此,如果Etherscan能找到验证错误的东西的方法,我就能以此为中心制作出真正绕过的谜题。

为了找出如何利用Etherscan的合同验证系统,必须验证几个合同。 我在Ropsten测试网络上引入了一些合同来折腾和验证它们。 很快,我们看到了以下界面。

选择了正确的设置,进入下一页。 在这里,我被要求提供合同源代码。

输入源代码后,点击了验证按钮。 果然,源代码现在附在合同里了。

我知道事情是怎么运作的,所以我可以嘲笑验证过程。 我首先尝试的是引进新合同,把foo改为bar,然后用原始源代码验证合同。 奇怪的是,Etherscan拒绝验证我的合同。

但是,当我手动比较双字节码的输出时,我发现很奇怪。 合同字节码必须是十六进制,但显然有些不是十六进制。

我知道将合同元数据附加到部署了solither的字节码上,但我从没想过它会如何影响合同的验证。 很明显,Etherscan正在扫描元数据的字节码,并将其替换为标签。 “这个区域内的东西什么都可以不同。 我们还在考虑同样的字节码。 ”

对于潜在的0日(零日)漏洞,这似乎是一条有前途的线索。 如果可以欺骗Etherscan,将元数据以外的东西解释为元数据,则可以调整在标记为{ipfs}的区域中展开的字节码,验证仍然是合法的字节码。

在创建事务中包括任何字节码的最简单方法是将其编码为构造函数的参数。 Solidity通过将ABI编码格式直接附加到创建事务数据中,对构造函数的参数进行编码。

但是,由于Etherscan很聪明,因此将构造函数的参数从所有类型的元数据嗅探器中排除。 可以看到构造函数的参数是斜体,表示与代码本身不同。

也就是说,必须以某种方式欺骗Solidity编译器,并发布字节序列,使其像嵌入的元数据一样进行控制。 但是,这似乎是一个很难解决的问题。 因为如果没有重大的编译器争论,就几乎无法控制索尔仁克使用的操作码和字节,之后源代码看起来就非常可疑了。

我就这个问题思考了一会儿。 直到索尼娅发现“几乎”发行任意字节其实非常简单。 以下代码会导致Solidity发出32字节的0xAA。

byte s32 value=0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,即xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

在鼓励下,我马上写了一份小合同。 它推送一系列常量,以便发出与嵌入了索力的元数据完全相似的字节码。

令人高兴的是,Etherscan在我的合同期间标记了IPFS哈希的存在。

我们快速复制了预期的字节码,用几个随机字节替换了IPFS散列,并引入了生成的合同。 果然,Etherscan一如既往地考虑不同的打工业务,并允许验证我的合同。

为此合同,建议在调用源代码为example ) )时返回简单的字节对象。 但是,如果你真的想叫它的话,就会发生这种事。

$ Seth call0x3CD 2138 CAB FB 03 C8 ED 9687561 A0 EF 5C 9a 153923 f ' Example () ) Seth-RPC :1,' JSON RPC ' : ' 2.0 '。 ' to ' : '0x3cd 2138 CAB FB 03 C8 ED 9687561 A0 EF 53 C9 A 153923 F ',' latest ' ' Seth-RPC 3:错误代码- 32000 Seth-RPC 333330代码

一个错误的开始

很明显,这个破解游戏围绕着这样的观点:在Etherscan上看到的源代码并不意味着合同的实际行为方式。 另外,由于希望玩家不要轻易直接播放交易,所以每个地址的解决方案必须是唯一的。 最好的方法显然是要求签名。

但是,什么情况下会要求玩家在一些数据上签名呢? 的第一个设计是具有单一公共函数的简单的puzzle。 玩家使用一些输入调用这个函数,签署数据证明他们提交了解决方案,如果输入通过了所有各种检查,他们就会被标记为solver。 但是,如果在接下来的几个小时内充实这个设计,我马上就会对事情的结果感到不满。 它变得非常沉重,开始变得不再优雅。 我受不了这样糟糕设计的puzzle毁了这样美妙的0日(零日)脆弱的想法。

我必须承认星期五之前做不完这件事,所以我决定睡觉了。

Pinball弹球难题

我周末试着重复了我的初期设计,但是没有取得更大的进展。 就像我现在的方法碰壁一样,虽然不想承认,但我知道如果我想要令人满意的东西,可能必须重新开始。

最终,我意识到自己从第一性原理重新审视了这个问题。 我想要的是破解游戏,玩家必须在其中完成各种知识检查。 但是,我并不要求完成知识测试本身就是取胜的条件。 相反,这可能是玩家可以选择的众多路径之一。 玩家可以在整个puzzle中累积分数,也许可以利用这个漏洞获得某种奖励。 因为获胜的条件只有最高的分数,所以间接鼓励使用漏洞。

请想起我去年设计的挑战,Lockbox。 它迫使玩家建立单一的数据块以满足六个不同的合同要求。 对同一字节应用不同的约束,玩家需要聪明地构建有效载荷。 我意识到我想在这里做类似的事情。 要求玩家提交单一数据blob。 根据符合特定要求的部分数据奖励分数。

在这一点上,我注意到我基本上是在解释pinboooll。 这是DEFCON CTF 2020决赛中面临的挑战。 pinboooll的噱头是,当运行二进制文件时,运行会在控制流图上反弹。 就像球在弹珠里反弹一样。 通过正确构建输入,可以找到特定的代码部分并得到分数。 当然也有漏洞,但坦率地说,我忘了那是什么,也不打算找。 再加上,我已经有自己想利用的漏洞了。

我在处理运行中的零迪漏洞,所以决定尽快解决这个问题。 最后,我花了几个小时让自己重新认识pinboooll的工作原理,花了几天时间重新实现它。 这样就解决了puzzle的支架问题。 现在只需要整合这个漏洞。

武装化一个零日漏洞

我让索尼娅输出正确字节的方法是,总是只加载一些常量,让索尼娅发出适当的推送指令。 但是,这样的任意常数可能是很大的危险信号。 我想要能更好地融入的东西。 我还必须加载一行的所有常量。 这用实际的代码很难说明。

因为我真的只是硬编码两个很棒的字节序列(0xa264…1220和0x6473…0033 ),所以我决定看看它们之间是否可以夹代码而不是第三个常数。 在已部署的合同中,只需要将中间的代码替换为其他命令。

地址a=0xa 264 . 1220; uintx=111…1; 地址b=0x 6473 . 0033; 一些实验结果表明,这是可能的,但前提是优化程序已启用。 否则,索氏体将发出过多的值清理代码。 这是可以接受的,所以我们将继续改进代码本身。

我只能在两个地址内修改代码,但是最后看到悬空的地址很奇怪,所以决定在条件句中使用它们。 我还得证明第二个条件的必要性,所以最后投了一点分数奖励。 我进行了第一次有条件的检查,检查了tx.origin是否与硬编码的值一致,给人一种不需要进一步追求这个代码路径的最初印象。

国际航空公司!=0x 13378 BD7Cacfcab 2909 FA 264697066735821220 (返回真; state.rand=0x40; state.location=0x60; IF (微软传感器!=0x 64736 F6 c 6343 a0f B 380033 c 82951 b 4126 BD 95042 (返回真; state.baseScore =1500; 源代码准备好了。 必须制作实际的后门。 我的后门需要验证玩家是否正确地触发了漏洞的利用。 如果他们没有正确触发,不给任何提示就失败,如果他们成功了,就会奖励他们。 因为希望漏洞不要轻易播放,所以决定让玩家签署自己的地址,在交易中提交签名。 为了增加乐趣,我决定要求签名在交易数据的偏移0x44处。 球通常从这里开始。 这需要玩家了解ABI代码的工作原理,然后手动将球数据重新定位到其他位置。

但是,在这里遇到了大问题。 不能将所有这些逻辑放入31字节的手写汇编中。 幸运的是,经过多方考虑,我发现其他31字节都可以使用。 毕竟,真正嵌入的元数据包含另一个IPFS散列,Etherscan也会忽略该散列。

打了几个码高尔夫之后,我到达了可以工作的后门。 第一个IPFS散列会立即弹出刚刚推送的地址,然后跳转到第二个IPFS散列。 然后,散列调用方,并部分设置内存/堆栈以调用ecrecover。 然后返回到第一个IPFS哈希,在那里完成堆栈的设置,然后执行调用。 最后,将分数乘数设定为(msg.sender==ecrecover ) ) *0x40 1。 也就是说,不需要额外的分支。

将后门编码到一定大小后,我在推特上发布了我的Rinkeby地址,从水龙头上获取了一些测试网ETH,暗示了看这条推文的任何人都有可能发生什么事。 其次,引入并验证了合同。

现在应该做的是等待有缘人找到隐藏在眼睛里的后门。

注:投稿时,Rocket Pool的软件开发者Kane Wallmann解开了这个谜题。 具体流程请参见此处: https://medium.com/@ kanewallmann _ 71759/an-untrustworthy-pinball Mann (71759/an-untrustworthy-pipine

此外,Etherscan开发者Caleb Lau也纠正了这一漏洞。

官方微信