Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
EVM虚拟机在解析合约的字节码时,依赖的是ABI的定义,从而去识别各个字段位于字节码的什么地方。一般ERC-20 TOKEN标准的代币都会实现transfer方法,这个方法在ERC-20标签中的定义为:function transfer(address to, uint tokens) public returns (bool success);9 h  z& V! v& Z3 r9 ?# _
2 s! L9 G/ Z# n( ]* _
第一参数是发送代币的目的地址,第二个参数是发送token的数量。5 {, k+ B! H4 u0 P4 X

% A) f9 R6 u. W+ R3 S当我们调用transfer函数向某个地址发送N个ERC-20代币的时候,交易的input数据分为3个部分:
9 j0 r& @* p7 o) Q
# W7 @+ p4 z# H* _4 字节,是方法名的哈希:a9059cbb
, _0 s, }+ N0 M" Z! g+ ]4 ?" C, f$ t8 }  O% {
32字节,放以太坊地址,目前以太坊地址是20个字节,高危补0, b$ |& c+ `1 a5 }+ k5 e
/ r9 \. q$ z: S6 m+ e! S0 o
000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca
8 p3 |0 t" Q# k5 s6 ]& t5 R1 N# X+ w: [. g
32字节,是需要传输的代币数量,这里是1*10^18 GNT
7 p3 T# B0 F( u. \  q) V& O0 P# L0 H8 |3 W
0000000000000000000000000000000000000000000000000de0b6b3a7640000
8 ?& s7 M' b, @2 J8 w
0 s( T& ^6 E! T$ Z) K所有这些加在一起就是交易数据:
+ y% l  Y1 Z- g- e" `. o1 d. c, n( l: v7 r1 n
a9059cbb000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca0000000000000000000000000000000000000000000000000de0b6b3a76400000 [' T! Q$ r) ], s! L- J

) J# Y- I) b/ c3 o* p* q5 ?0x01 以太坊短地址
6 ]" {" I' S; X5 R% m  x* r
; i* |7 r! X& d; N当调用transfer方法提币时,如果允许用户输入了一个短地址,这里通常是交易所这里没有做处理,比如没有校验用户输入的地址长度是否合法。8 y: u' z' Z/ ?9 [" P8 F3 M

2 J' Z7 F5 o+ H3 m如果一个以太坊地址如下,注意到结尾为0:% j0 k4 c. ~% c$ T2 G% D6 [

* d/ O+ C: C! C9 `) E) m- Q5 H1 W5 M, g0x1234567890123456789012345678901234567800: D$ \9 U" d5 O/ ~  a% g
: u  w$ D) t# u( i: Y
当我们将后面的00省略时,EVM会从下一个参数的高位拿到00来补充,这就会导致一些问题了。
5 [9 I, A6 B2 ^% c, Y7 b8 V% Q6 k: Q' p% l/ g
这时,token数量参数其实就会少了1个字节,即token数量左移了一个字节,使得合约多发送很多代币出来。我们看个例子:
- r6 c- u" _- b+ ^4 t$ Y( W' 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
1 C' N* Y6 R5 t, @: k! }6 Y& b
& w! j6 Y( t3 W7 Q这里的0x90b98a11是method的hash值,第二个是地址,第三个是amount参数。
9 f$ t0 V. K+ u; E9 f) u
# X6 u9 s4 y1 E# [4 U' q. P/ l如果我们调用sendCoin方法的时候,传入地址0x62bec9abe373123b9b635b75608f94eb8644163e,把这个地址的“3e”丢掉,即扔掉末尾的一个字节,参数就变成了:) ~$ R8 S; E6 Z: r

* H) h, N. c. |8 P# z% q0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb86441600 00000000000000000000000000000000000000000000000000000000000002                                                               ^^                              缺失1个字节
% S; e# b; G; q/ i% T+ q1 I7 l2 T$ \6 p, K& O8 ~; ]' R2 k3 n
这里EVM把amount的高位的一个字节的0填充到了address部分,这样使得amount向左移位了1个字节,即向左移位8。
0 s. m# L( c! n3 ?. m0 d
4 p2 a$ }  V3 j这样,amount就成了2* p% O& J8 I, G' J3 |9 A
! o$ Z8 A, y6 P* k
0x02 构造短地址攻击7 C0 F4 b/ N& K

$ w' l2 P7 N' y3 i. ]4 B(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

" H0 l" o+ x7 u(3)往这个钱包发送1000个币
4 w/ f: c7 `9 C  L" v' t2 e: E$ }2 F' M) u8 R5 z
(4)然后再从这个钱包中提出1000个币,当然这时候写地址的时候把最后两个0去掉$ F/ e- l! i% l$ \

! C0 K4 b4 q6 r  H; x  d如果交易所并没有校验用户填入的以太坊地址,则EVM会把所有函数的参数一起打包,会把amount参数的高位1个字节吃掉。
+ `! b' ]! S8 e  d$ T  t' U6 F0 V  Y* t5 h
(5)这三个参数会被传入到msg.data中,然后调用合约的transfer方法,此时,amount由于高位的1个字节被吃掉了,因此amount = amount
  C) B, R0 w# W! U9 ~) j! m# T$ p, `! b
0x03 总结# d8 p* t$ j$ ^2 z7 P7 `
" y' {1 a8 g! t# Y' d! r
针对这个漏洞,说实话以太坊有不可推卸的责任,因为EVM并没有严格校验地址的位数,并且还擅自自动补充消失的位数。此外,交易所在提币的时候,需要严格校验用户输入的地址,这样可以尽早在前端就禁止掉恶意的短地址。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

ddgghhjjkk 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1