Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
EVM虚拟机在解析合约的字节码时,依赖的是ABI的定义,从而去识别各个字段位于字节码的什么地方。一般ERC-20 TOKEN标准的代币都会实现transfer方法,这个方法在ERC-20标签中的定义为:function transfer(address to, uint tokens) public returns (bool success);3 w4 e" N/ ~# Y1 T3 p6 j
2 n. `& d3 l9 \; o' r; ?* H, n: N
第一参数是发送代币的目的地址,第二个参数是发送token的数量。) A: l) N8 X6 s; J; g) C. ]
8 ]7 x% \! Q+ T$ O
当我们调用transfer函数向某个地址发送N个ERC-20代币的时候,交易的input数据分为3个部分:
% c) Y. S. d1 g$ C7 j: A
9 B  Q" u3 N2 N4 q9 W: H4 字节,是方法名的哈希:a9059cbb+ H- [4 `+ X* U* i3 p: B+ o) ]. j
/ p; p: E5 j  A9 P) y7 x/ c
32字节,放以太坊地址,目前以太坊地址是20个字节,高危补0+ Q2 D. E2 Z( Q) B  s) b3 C0 \4 G

3 C* L) d! A6 @, `/ T+ ?) X  w  k000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca) b$ v5 E5 |  B, p. j! k/ r
- j2 }+ t+ C  L: f, F3 \; h3 c  E
32字节,是需要传输的代币数量,这里是1*10^18 GNT
9 F# z, o4 v; v5 l5 X: ?! W
! r  e* ?$ z5 J) k0000000000000000000000000000000000000000000000000de0b6b3a7640000
& n& N+ R2 R4 n3 m" c8 v1 ^" w& F+ i/ e4 q3 X, v
所有这些加在一起就是交易数据:6 y6 }: F0 I1 a! h0 n# d" p

- w8 X" q) G' [7 ^0 J; Za9059cbb000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca0000000000000000000000000000000000000000000000000de0b6b3a7640000
+ o7 q& o* L8 T& P+ Q, H* F9 h7 |6 U+ `9 j. j
0x01 以太坊短地址5 F# N* O. c4 n  a$ o

+ s% |2 u$ n! s0 ^. ^/ u当调用transfer方法提币时,如果允许用户输入了一个短地址,这里通常是交易所这里没有做处理,比如没有校验用户输入的地址长度是否合法。
) W6 x# H0 n; J. J! B9 N8 q/ B1 x1 y8 l
如果一个以太坊地址如下,注意到结尾为0:
+ j2 N  P1 C1 h2 H# g, `, ~: o& e9 `4 l
0x1234567890123456789012345678901234567800
" Z# B( x  g  E. [- P% P5 i3 s7 h$ n' L7 x5 \
当我们将后面的00省略时,EVM会从下一个参数的高位拿到00来补充,这就会导致一些问题了。, ^0 R! I0 s9 |$ s7 [

7 J( r* {. r$ \3 j9 U9 E, w0 @% B这时,token数量参数其实就会少了1个字节,即token数量左移了一个字节,使得合约多发送很多代币出来。我们看个例子:
1 q& d$ `( v" f; G" D) L$ X
, x6 R3 C. m$ M7 F9 |  p7 @" K  t这里调用sendCoin方法时,传入的参数如下:
, E7 D* _3 N, {9 c
- ~3 }$ A5 }, `# J0 k. E0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb8644163e 0000000000000000000000000000000000000000000000000000000000000002
! S( k4 h, p- Y, p( n7 f7 }- i; R. U' l6 o1 j  h
这里的0x90b98a11是method的hash值,第二个是地址,第三个是amount参数。
3 [9 ]' w' U0 c/ Z
, J8 u* z  ]; a0 w# q( b# O2 r! @如果我们调用sendCoin方法的时候,传入地址0x62bec9abe373123b9b635b75608f94eb8644163e,把这个地址的“3e”丢掉,即扔掉末尾的一个字节,参数就变成了:- }5 ?$ e  q. X8 \8 O8 P8 r( N: x
/ H: c$ q1 `' y3 Y# c+ Y" t
0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb86441600 00000000000000000000000000000000000000000000000000000000000002                                                               ^^                              缺失1个字节
$ c5 i( n9 e& f$ y7 L7 [2 d# k, l1 @) {. t0 i; z1 \' Y
这里EVM把amount的高位的一个字节的0填充到了address部分,这样使得amount向左移位了1个字节,即向左移位8。
# c: @! J, ]# X, g8 K  ^# ~! q9 |1 [1 Y! @
这样,amount就成了2) R( @3 i! n% p! M* v
* o$ u+ ^% f, f! d/ }
0x02 构造短地址攻击
* L0 s* K6 j) Z8 A9 n) E6 v5 i' N6 Q% `, ~: I2 d
(1)首先生成一个ETH的靓号,这个账号末尾为2个0
. G3 e" p' N; _" N3 I2 q; w8 X; y  p# s* l' H, J! g6 |/ @
使用一些跑号工具就可以做到,比如MyLinkToken工具,可以很轻易跑出末尾两个0的。* {5 c$ X$ S# a' i" F" |& p8 g9 C  u
- e, P1 I: o& G3 U: m2 f  h7 K
(2)找一个交易所钱包,该钱包里token数量为256000
) q) J+ n9 ]6 n0 d
3 V6 ~3 M3 I+ X$ p2 K2 E(3)往这个钱包发送1000个币
: S3 X. y8 p0 V1 i' h' E* a) P3 S. I9 L
(4)然后再从这个钱包中提出1000个币,当然这时候写地址的时候把最后两个0去掉
) }/ S3 ~* u9 t% O) M/ s' ?' o7 O, @5 n
如果交易所并没有校验用户填入的以太坊地址,则EVM会把所有函数的参数一起打包,会把amount参数的高位1个字节吃掉。
4 T* s( d" e3 A3 m8 U" j/ K3 }
' ?* Y6 }- v' O1 y3 c  {(5)这三个参数会被传入到msg.data中,然后调用合约的transfer方法,此时,amount由于高位的1个字节被吃掉了,因此amount = amount
! E1 A( w- f# D7 b2 N+ E; x# @7 l7 ]1 A: L
0x03 总结. j2 j# b9 S: [2 b/ U

5 O: M: w+ E5 C/ a8 e  o) s1 p针对这个漏洞,说实话以太坊有不可推卸的责任,因为EVM并没有严格校验地址的位数,并且还擅自自动补充消失的位数。此外,交易所在提币的时候,需要严格校验用户输入的地址,这样可以尽早在前端就禁止掉恶意的短地址。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

ddgghhjjkk 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1