EVM并没有严格校验 可以发起以太坊短地址攻击
ddgghhjjkk
发表于 2022-12-15 09:11:23
96
0
0
& W3 M3 y3 m7 @5 ?
第一参数是发送代币的目的地址,第二个参数是发送token的数量。
当我们调用transfer函数向某个地址发送N个ERC-20代币的时候,交易的input数据分为3个部分:9 w7 L \4 d M/ C: J
4 字节,是方法名的哈希:a9059cbb
" u7 y K1 X" S8 B' C( b
32字节,放以太坊地址,目前以太坊地址是20个字节,高危补09 E2 D! g/ k' f: N
$ ~. f/ ?/ l# [) C0 j
000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca" X( B9 j6 [0 S, n- d! ?: n* p2 D
32字节,是需要传输的代币数量,这里是1*10^18 GNT, k7 N' ?8 {# z6 Q
0000000000000000000000000000000000000000000000000de0b6b3a7640000
所有这些加在一起就是交易数据:' e5 h4 c$ \, }9 Z( B, [2 g
) \. A9 S% `* s3 y
a9059cbb000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca0000000000000000000000000000000000000000000000000de0b6b3a7640000
x. }! o' H- ?
0x01 以太坊短地址
当调用transfer方法提币时,如果允许用户输入了一个短地址,这里通常是交易所这里没有做处理,比如没有校验用户输入的地址长度是否合法。( @) R0 N, P+ e4 T0 a( K
1 F" v P2 e5 ] g/ r5 g/ p
如果一个以太坊地址如下,注意到结尾为0:
0x1234567890123456789012345678901234567800
当我们将后面的00省略时,EVM会从下一个参数的高位拿到00来补充,这就会导致一些问题了。6 e6 k( p( X" t+ W
1 ~! H! `8 m' M7 a
这时,token数量参数其实就会少了1个字节,即token数量左移了一个字节,使得合约多发送很多代币出来。我们看个例子:. g( f, y% |! g1 d9 O" `
这里调用sendCoin方法时,传入的参数如下:
0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb8644163e 0000000000000000000000000000000000000000000000000000000000000002
这里的0x90b98a11是method的hash值,第二个是地址,第三个是amount参数。
如果我们调用sendCoin方法的时候,传入地址0x62bec9abe373123b9b635b75608f94eb8644163e,把这个地址的“3e”丢掉,即扔掉末尾的一个字节,参数就变成了:+ T3 N; `7 N* ^+ J0 W7 H: j
0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb86441600 00000000000000000000000000000000000000000000000000000000000002 ^^ 缺失1个字节! e% g( A1 f7 V' a4 P' v
这里EVM把amount的高位的一个字节的0填充到了address部分,这样使得amount向左移位了1个字节,即向左移位8。
这样,amount就成了2$ V: ]4 }3 k- v
& u; y& c0 Y7 m: Y4 j
0x02 构造短地址攻击 o; o+ F7 c/ U9 j, p9 ^
(1)首先生成一个ETH的靓号,这个账号末尾为2个03 z z: X- R6 R" }
/ R; J( h# d1 J. x9 f: n% v# R
使用一些跑号工具就可以做到,比如MyLinkToken工具,可以很轻易跑出末尾两个0的。, }6 H' I3 R5 ~/ e/ ]
1 X0 Y% J* E3 J: ~) t2 l
(2)找一个交易所钱包,该钱包里token数量为256000# r% r3 x; V' |1 r/ a' x% v8 f" _5 B
& ?1 u4 @- U0 q& E, X ]
(3)往这个钱包发送1000个币) U( R1 ?$ G- v5 e
2 a% A0 d/ m2 T# w2 T: O! z
(4)然后再从这个钱包中提出1000个币,当然这时候写地址的时候把最后两个0去掉) s& ?3 V; s |$ X! t( g
0 {! k* K3 |2 U! D+ d
如果交易所并没有校验用户填入的以太坊地址,则EVM会把所有函数的参数一起打包,会把amount参数的高位1个字节吃掉。
& u: E4 K1 T: J$ c- w2 Z8 _" b1 G
(5)这三个参数会被传入到msg.data中,然后调用合约的transfer方法,此时,amount由于高位的1个字节被吃掉了,因此amount = amount7 h n; z4 p* z) S
. U# l$ E4 b; p# o& Z
0x03 总结
针对这个漏洞,说实话以太坊有不可推卸的责任,因为EVM并没有严格校验地址的位数,并且还擅自自动补充消失的位数。此外,交易所在提币的时候,需要严格校验用户输入的地址,这样可以尽早在前端就禁止掉恶意的短地址。
成为第一个吐槽的人