遗忘的亚特兰蒂斯:以太坊短地址攻击详解
0 概述
说到智能合约漏洞,第一时间映入脑海的可能都是算法溢出,call()函数滥用,假充值等漏洞,毕竟这是在很多智能合约上都有实例,并且危害等级也是比较高的,但是有一个漏洞也许很多人都见过、听过却不是很多人都关心的漏洞,它就像是人类世界的亚特兰蒂斯,很多人知道,却很少有研究报告,Google 上能找到的,也不过只是说原理而没有复现实战,有点纸上谈兵的感觉。大家都知道的是这是 EVM 层面的缺陷,而不是智能合约层面的问题,并且在我们默认的思维里面,这是一个已经被修复的漏洞。前段时间尝试翻查短地址攻击的官方修复方案,但是经过我的搜索,并没有找到相关的修复方案,Github 上也扒了一遍,也看不到历史 release 有相关的修复,于是,我猜,真的是我猜,EVM 层面可能并没有修复。
1 短地址攻击基础知识
短地址攻击其实就是每个 ERC20 的合约里面都有一个以下的函数
当对合约的这个函数进行调用的时候,其实在 EVM 层面来说是传入一串字节码,就像下图这样,可以在 Etherscan 里面查看每笔交易的 inputdata 里面的整个函数的调用数据
传入的字节码一共有 136 字节(正常来说),里面包含方法的签名(前 4 字节),和传入的参数值(数据部分,包括传入的地址数据和金额数据,分别都为 32 字节,高位补零)。上面这个图是不正常的,只有 134 字节,这是我经过特殊处理过的,下面我会详细说。
从上面的信息我们可以知道,EVM 是根据字节码识别传入的参数的,字节码是多少就是多少,也不会去验证。巧了,就是这样,漏洞就产生了,有人就想用不合法的地址,比如地址故意写少后几位,看看 EVM 会怎么处理,但是又巧了,EVM 不仅不会报错,还会“贴心”的帮你对地址进行补全操作,怎么补全的呢?就是将地址后面不足的部分,用金额数据部分的位数来补全,比方说你的地址本来是
结果由于你心机叵测,故意写少两个 0,变成下面这样
那么“贴心”的 EVM 就会从字节码中的金额数据部分取两位对地址进行补全,而金额数据部分的前两位又恰好是 0,那么就是说你的地址还是原来的地址,但是数据部分就少 2 位了,怎么办呢?这就不符合 ABI 的字节数啦,没关系,“贴心”的 EVM 会将你的金额数据部分从末位开始补 0,补到为正常的 136 字节为止,那么有同学就要问了,如果我的地址有 6 个 0,那么我地址故意写少 6 个 0,是不是数据部分就多了 6 个 0?那不是发财了?
答案就是:你是对的
也就是说,本来填的数据是 1,变成字节码后是 0x1,如果地址少了 6 个字节,那么你的 data 就自动变成 0x1000000 啦!惊不惊喜,意不意外!
2 第一次出师
第一次我尝试使用 remix 进行复现,但结果是能预料到失败的,如下图,为什么呢?因为这是一个在 2017 年就被爆出的漏洞,修复方案满天飞,怎么可能那么简单的就让你成功了呢,所以前端肯定会对你的输入的地址进行过滤和检查,想成功,是 naive 的。
但是作为一个搞事情的人,怎么可以轻言放弃,既然没有找到官方修复方案,底层肯定就还有问题的,于是乎,我只能从最底层开始进行操作,我想到了使用 web3 进行漏洞复现
3 环境准备
1. 操作系统:macOS 2. node : v8.11.0 3. web3:1.0.0-beta.36 4. rpc:infura 5. 测试合约的 abi 6. 示例合约:
7. 使用 remix 在测试网部署示例合约,获取合约的地址,下面会用到 ⚠️获取 abi 的方法:
4 第二次出师
注:(⚠️本次所有操作均在命令行中执行)
1. 键入 node 进入命令行提示符 2. 在项目中引入 web3 并设置 provider(怎么下载 web3 这里不展开说明,有兴趣的可以自己查找,一个很简单的操作)
3. 创建合约实例:
4. 构造方法 abi,也就是构造我们上面说的交易里面的 inputdata,由于我们是要构造短地址攻击,所以我们的地址是要比正常的地址的位数要少的,为的就是要让 EVM 用零自动补全缺失的地址,但是正常的构造是会失败的,例如下图这样
但是,再次声明一下,作为一个搞事情的人,不能轻言放弃!于是我们需要一点特别的方法,一开始的时候我到了这里就以为会有检测就不行了,太天真,其实是 web3 的检测,我们需要一点特别的方法。这个方法分为两步
第一步,先构造正常的 abi,这次使用的地址是 '0xdfca6234eb09125632f8f3c71bf8733073b7cd00'
如图,现在的 abi,也就是 inputdata,是 136 字节的。
第二步:使用一个小技巧,将 abi 里面地址后面的两个零偷偷抹掉,本来是 136 字节的,现在只有 134 字节了,也就是我上面说到的不正常的 inputdata,就是在这个时候构造出来的
以上就是把零抹掉之后的 abi
ok,一切都准备好之后就可以到最激动人心的时刻了
5. 在项目中引入 ethereumjs-tx(怎么下载的这里也不详细展开)
6. 导入你的私钥并做一些处理:
7. 构造原始交易数据,这是一笔十分原生的以太坊交易数据,每一次的合约调用,其实都会构造下面这一个数据。有关这方面的知识也不详细展开,但是,除了 nonce 我们是不怎么了解之外,其他都是我们在 remix 上调用合约的时候会接触到的,有关于 nonce 的说明,其实就是帐号所发送的交易数量,比方说你的帐号曾经处理过 5 笔交易,那么 nonce 就等于4(nonce 从 0 开始),可以在 ehterscan 上查看到你的帐号的最后一笔交易的 nonce,以下是具体的交易数据:
8. 对交易进行签名和对交易做一点处理
9. 发送交易
5 奇迹再现
通过预先设置的 event 事件我们可以看到,EVM 成功补零,输入本来是 123,但是 EVM 提取的结果却是 31488,本来的 16 进制 123 是 0x7b,现在是 0x7b00!刺激!
Công nghệ Ethereum có thể sẽ cắt giảm một nửa thị phần của Bitcoin
Đồng tiền mã hóa hỗ trợ mạng Ethereum, blockchain phổ biến nhất thế giới cho những liên doanh về tiề...
Phân tích giá 20/9: Bitcoin, Ethereum, Ripple, Bitcoin Cash, EOS, Stellar, Litecoin, Cardano, Monero, IOTA.
Thị trường đang có dấu hiệu, các đồng coin hiện không còn phải chịu áp lực lớn từ phe gấu. Các đề xu...
Chủ tịch SEC làm rõ về những bình luận xung quanh Ethereum và Ripple
Trong thời gian vừa qua, đã có rất nhiều những bình luận về Ethereum được đưa ra từ SEC. Và cuối tuầ...