EVM并没有严格校验 可以发起以太坊短地址攻击
ddgghhjjkk
发表于 2022-12-15 09:11:23
124
0
0
2 s! L9 G/ Z# n( ]* _
第一参数是发送代币的目的地址,第二个参数是发送token的数量。5 {, k+ B! H4 u0 P4 X
当我们调用transfer函数向某个地址发送N个ERC-20代币的时候,交易的input数据分为3个部分:
4 字节,是方法名的哈希:a9059cbb
! g+ ]4 ?" C, f$ t8 } O% {
32字节,放以太坊地址,目前以太坊地址是20个字节,高危补0, b$ |& c+ `1 a5 }+ k5 e
/ r9 \. q$ z: S6 m+ e! S0 o
000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca
& t5 R1 N# X+ w: [. g
32字节,是需要传输的代币数量,这里是1*10^18 GNT
q) V& O0 P# L0 H8 |3 W
0000000000000000000000000000000000000000000000000de0b6b3a7640000
所有这些加在一起就是交易数据:
- e" `. o1 d. c, n( l: v7 r1 n
a9059cbb000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca0000000000000000000000000000000000000000000000000de0b6b3a76400000 [' T! Q$ r) ], s! L- J
0x01 以太坊短地址
当调用transfer方法提币时,如果允许用户输入了一个短地址,这里通常是交易所这里没有做处理,比如没有校验用户输入的地址长度是否合法。8 y: u' z' Z/ ?9 [" P8 F3 M
如果一个以太坊地址如下,注意到结尾为0:% j0 k4 c. ~% c$ T2 G% D6 [
0x1234567890123456789012345678901234567800: D$ \9 U" d5 O/ ~ a% g
: u w$ D) t# u( i: Y
当我们将后面的00省略时,EVM会从下一个参数的高位拿到00来补充,这就会导致一些问题了。
7 b8 V% Q6 k: Q' p% l/ g
这时,token数量参数其实就会少了1个字节,即token数量左移了一个字节,使得合约多发送很多代币出来。我们看个例子:
' N0 W i; Y# s( U* s1 o" H
这里调用sendCoin方法时,传入的参数如下:7 @( Z% i! f# N+ z
8 r$ \& p7 O' j+ M1 s
0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb8644163e 0000000000000000000000000000000000000000000000000000000000000002
这里的0x90b98a11是method的hash值,第二个是地址,第三个是amount参数。
如果我们调用sendCoin方法的时候,传入地址0x62bec9abe373123b9b635b75608f94eb8644163e,把这个地址的“3e”丢掉,即扔掉末尾的一个字节,参数就变成了:) ~$ R8 S; E6 Z: r
0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb86441600 00000000000000000000000000000000000000000000000000000000000002 ^^ 缺失1个字节
2 T$ \6 p, K& O8 ~; ]' R2 k3 n
这里EVM把amount的高位的一个字节的0填充到了address部分,这样使得amount向左移位了1个字节,即向左移位8。
这样,amount就成了2* p% O& J8 I, G' J3 |9 A
! o$ Z8 A, y6 P* k
0x02 构造短地址攻击7 C0 F4 b/ N& K
(1)首先生成一个ETH的靓号,这个账号末尾为2个0/ V" j1 v+ j1 W& G5 K) I& D
) h3 a, E# o7 W) J
使用一些跑号工具就可以做到,比如MyLinkToken工具,可以很轻易跑出末尾两个0的。3 a* O* @) \% j a5 ]8 ]
6 C. Y" G+ j- z# K6 ^/ J5 a
(2)找一个交易所钱包,该钱包里token数量为256000# G) P, v; G, s j8 b! T
(3)往这个钱包发送1000个币
2 e: E$ }2 F' M) u8 R5 z
(4)然后再从这个钱包中提出1000个币,当然这时候写地址的时候把最后两个0去掉$ F/ e- l! i% l$ \
如果交易所并没有校验用户填入的以太坊地址,则EVM会把所有函数的参数一起打包,会把amount参数的高位1个字节吃掉。
' U6 F0 V Y* t5 h
(5)这三个参数会被传入到msg.data中,然后调用合约的transfer方法,此时,amount由于高位的1个字节被吃掉了,因此amount = amount
9 ~) j! m# T$ p, `! b
0x03 总结# d8 p* t$ j$ ^2 z7 P7 `
" y' {1 a8 g! t# Y' d! r
针对这个漏洞,说实话以太坊有不可推卸的责任,因为EVM并没有严格校验地址的位数,并且还擅自自动补充消失的位数。此外,交易所在提币的时候,需要严格校验用户输入的地址,这样可以尽早在前端就禁止掉恶意的短地址。
成为第一个吐槽的人