EVM并没有严格校验 可以发起以太坊短地址攻击
ddgghhjjkk
发表于 2022-12-15 09:11:23
161
0
0
第一参数是发送代币的目的地址,第二个参数是发送token的数量。2 A: c) G% H. h
+ I4 M( M! E- u. h1 A# f9 x
当我们调用transfer函数向某个地址发送N个ERC-20代币的时候,交易的input数据分为3个部分:! W2 D3 ]5 A& }) L2 m
4 字节,是方法名的哈希:a9059cbb) y2 G. G ~& t, B, P3 j0 Y
32字节,放以太坊地址,目前以太坊地址是20个字节,高危补0
M- W* ^. ^; D7 N* g* ?
000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca
" H1 B% H2 N/ b, m7 P, [, T
32字节,是需要传输的代币数量,这里是1*10^18 GNT; ~& i7 c. k1 n4 z( M' Q
0000000000000000000000000000000000000000000000000de0b6b3a7640000! ^+ q* F. e1 ^" E. }% b' C9 |* }5 J0 d' A
' {8 }, k! v3 A; ~ x1 Q( X
所有这些加在一起就是交易数据:2 s# V( H7 ]5 G8 J; X$ H" W
# @- \5 ~: Z& d# F& e8 c
a9059cbb000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca0000000000000000000000000000000000000000000000000de0b6b3a7640000
0 d, H$ G! o, P* x
0x01 以太坊短地址
当调用transfer方法提币时,如果允许用户输入了一个短地址,这里通常是交易所这里没有做处理,比如没有校验用户输入的地址长度是否合法。
' T* T2 w. w6 J' q2 o8 b' w' R9 Y
如果一个以太坊地址如下,注意到结尾为0:
" c/ B7 I. T$ w8 k" T
0x1234567890123456789012345678901234567800
0 y; a6 |9 F6 }, F5 S
当我们将后面的00省略时,EVM会从下一个参数的高位拿到00来补充,这就会导致一些问题了。9 V1 f; Y: m: O
这时,token数量参数其实就会少了1个字节,即token数量左移了一个字节,使得合约多发送很多代币出来。我们看个例子:! x% G# Q& O6 }* b
" _. k) r+ h5 }/ G1 Y
这里调用sendCoin方法时,传入的参数如下:
0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb8644163e 00000000000000000000000000000000000000000000000000000000000000028 t- \3 `. b! t# t. K
8 z& [# V r2 f% L1 x, R5 v* w
这里的0x90b98a11是method的hash值,第二个是地址,第三个是amount参数。, d' ~" I: k; ^1 \2 A
+ M/ m2 J- ^3 q& H4 k
如果我们调用sendCoin方法的时候,传入地址0x62bec9abe373123b9b635b75608f94eb8644163e,把这个地址的“3e”丢掉,即扔掉末尾的一个字节,参数就变成了:- v8 j/ V" M! N7 \1 X* |
! ^& q+ x- T% L8 o, X& l
0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb86441600 00000000000000000000000000000000000000000000000000000000000002 ^^ 缺失1个字节/ s( D6 ^8 k& @3 _. v
这里EVM把amount的高位的一个字节的0填充到了address部分,这样使得amount向左移位了1个字节,即向左移位8。2 j/ S4 r$ |7 }) e/ N
# l6 \$ F3 U8 i7 a' A
这样,amount就成了2; ~) Z$ N, _/ e$ \. }7 L9 Y: O
5 [0 {, ~+ [9 {9 Q1 q- t2 g+ c
0x02 构造短地址攻击$ c- b' f3 K. @/ u4 d3 N3 C8 w f
) F& {: v* t6 {
(1)首先生成一个ETH的靓号,这个账号末尾为2个05 { ]$ c8 F" ?4 Z9 }
- U; T) ?# H0 i
使用一些跑号工具就可以做到,比如MyLinkToken工具,可以很轻易跑出末尾两个0的。' c: N5 Q- L' f+ r O" l
(2)找一个交易所钱包,该钱包里token数量为2560008 a& x+ C. A9 R; I1 s
(3)往这个钱包发送1000个币7 x7 R* i$ h. ?' h1 E
(4)然后再从这个钱包中提出1000个币,当然这时候写地址的时候把最后两个0去掉3 Y- ?( ~+ {( m' b6 o
5 n- N, U$ s6 a% ]
如果交易所并没有校验用户填入的以太坊地址,则EVM会把所有函数的参数一起打包,会把amount参数的高位1个字节吃掉。/ p& K+ v9 ?* l; D. `0 g. P% i- T# \0 R
+ i5 O7 N, { R8 w
(5)这三个参数会被传入到msg.data中,然后调用合约的transfer方法,此时,amount由于高位的1个字节被吃掉了,因此amount = amount
9 `* Z6 M- u# o+ G9 E
0x03 总结3 W% o# z; }# T5 P2 P
针对这个漏洞,说实话以太坊有不可推卸的责任,因为EVM并没有严格校验地址的位数,并且还擅自自动补充消失的位数。此外,交易所在提币的时候,需要严格校验用户输入的地址,这样可以尽早在前端就禁止掉恶意的短地址。
成为第一个吐槽的人