Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
EVM虚拟机在解析合约的字节码时,依赖的是ABI的定义,从而去识别各个字段位于字节码的什么地方。一般ERC-20 TOKEN标准的代币都会实现transfer方法,这个方法在ERC-20标签中的定义为:function transfer(address to, uint tokens) public returns (bool success);
( D/ Q- P& n. P: A) @# x- j/ e9 Q0 x  M# i( N( H  j7 C
第一参数是发送代币的目的地址,第二个参数是发送token的数量。
4 M9 D% R1 f- y/ B
+ I* _& l+ a' p当我们调用transfer函数向某个地址发送N个ERC-20代币的时候,交易的input数据分为3个部分:5 q9 ]% _* C% W& g3 W" v& @
3 O" i& e; ]9 e9 w5 D8 E" |
4 字节,是方法名的哈希:a9059cbb% p3 ^3 L' Y& i% z1 _

* U: Z) K: u2 M1 [( l$ ~. H32字节,放以太坊地址,目前以太坊地址是20个字节,高危补0
6 `2 ~( V8 f- i/ [% J+ \9 N! n: y& }! Y* F% e  V
000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca
1 R2 w3 ~9 L; l% `+ a# p. S1 ?$ l
9 Q( m0 \1 `% o* y3 i( A! K/ j32字节,是需要传输的代币数量,这里是1*10^18 GNT! ]- U) y; d- Y$ ]

0 o) F4 S. W# P3 ~% e# B2 Q0000000000000000000000000000000000000000000000000de0b6b3a7640000% R+ u' n5 z( n" |% u9 F

& N9 l6 u( d1 q9 N; L所有这些加在一起就是交易数据:; C$ ^5 {4 b  o  h

! Z& a1 a; V& Y# f/ e' Oa9059cbb000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca0000000000000000000000000000000000000000000000000de0b6b3a7640000
$ x! k0 |. Y' ~; s
2 {; c7 G% c1 i9 A8 s) V3 w/ U) n0x01 以太坊短地址' h  m8 C2 i8 d: M" Z4 x
  p5 V- u1 Y1 @3 ?  w" }  Z3 m
当调用transfer方法提币时,如果允许用户输入了一个短地址,这里通常是交易所这里没有做处理,比如没有校验用户输入的地址长度是否合法。
- b" V' T9 B: v+ x: p9 {% H" X, s0 {0 [
如果一个以太坊地址如下,注意到结尾为0:$ U" p1 d* m! |6 }1 }! {

: g4 u$ \& r. V  E! J- w0x1234567890123456789012345678901234567800
& @- d0 E" I& S9 u
1 q: l: Z$ V' {4 u  l当我们将后面的00省略时,EVM会从下一个参数的高位拿到00来补充,这就会导致一些问题了。
0 K) u: t* q3 d! L
  c) r0 \4 Q" _5 T0 s. J这时,token数量参数其实就会少了1个字节,即token数量左移了一个字节,使得合约多发送很多代币出来。我们看个例子:
; i2 A8 M9 ?. D% b& T  w' z- ^6 ?* J2 Z) K0 l: C) j* x  O
这里调用sendCoin方法时,传入的参数如下:4 i- ?1 h8 S: y; j! h
! b$ F8 @( k! ^, g" f& V
0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb8644163e 0000000000000000000000000000000000000000000000000000000000000002
& M9 _) v% P# a0 H8 f( d0 f* Z5 Q) w
6 c1 p& {0 m/ ]# G3 V这里的0x90b98a11是method的hash值,第二个是地址,第三个是amount参数。# P* z) |- u5 p1 {0 E  l4 F

. T( G8 C1 M& x) M: a7 t' e如果我们调用sendCoin方法的时候,传入地址0x62bec9abe373123b9b635b75608f94eb8644163e,把这个地址的“3e”丢掉,即扔掉末尾的一个字节,参数就变成了:" n% B* |# d; n
8 ?7 B( K- U6 h1 }, s+ j
0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb86441600 00000000000000000000000000000000000000000000000000000000000002                                                               ^^                              缺失1个字节- T* C7 i2 q5 M+ n% v% X* I
& A% v; C3 g& i" \. B
这里EVM把amount的高位的一个字节的0填充到了address部分,这样使得amount向左移位了1个字节,即向左移位8。, U) b5 }* r1 E8 [* z% L

0 k. _$ S$ C0 x这样,amount就成了2: @/ d/ e/ Z0 J2 N1 I9 `* ]* d% V
5 t* t# W8 [7 r& r! p$ V6 M3 |
0x02 构造短地址攻击
: Z" S$ h3 b8 \$ L* W' _
  f# w# w* o% c1 X& B(1)首先生成一个ETH的靓号,这个账号末尾为2个0, j; o1 y  g2 |* Y
" I6 f' t1 a$ K' A: C+ \
使用一些跑号工具就可以做到,比如MyLinkToken工具,可以很轻易跑出末尾两个0的。& h  n! u. p% N. _

; a4 ^$ a7 r# t(2)找一个交易所钱包,该钱包里token数量为256000
  |) H# D" M0 u- h; J9 {4 E* J9 i( g* R" U6 Q' _8 s. S
(3)往这个钱包发送1000个币7 }$ {9 R$ a& U+ W4 f# |; S

; ~" L5 k" `: I7 h' [. U& u(4)然后再从这个钱包中提出1000个币,当然这时候写地址的时候把最后两个0去掉3 i8 O) y& N7 |9 b9 b: i% v
1 ~9 X7 _% w& ?; E" c+ K# q8 P
如果交易所并没有校验用户填入的以太坊地址,则EVM会把所有函数的参数一起打包,会把amount参数的高位1个字节吃掉。; k% K  Q! L3 y! a' H

" l8 V5 O& O% s' Y(5)这三个参数会被传入到msg.data中,然后调用合约的transfer方法,此时,amount由于高位的1个字节被吃掉了,因此amount = amount6 U* n1 c' b* D- ]3 i

0 E- l( V) F; F9 U4 ~0x03 总结1 O, q  i' Y2 L. z0 G1 m
& }# p! }$ H3 @# h9 H& P$ i6 ?
针对这个漏洞,说实话以太坊有不可推卸的责任,因为EVM并没有严格校验地址的位数,并且还擅自自动补充消失的位数。此外,交易所在提币的时候,需要严格校验用户输入的地址,这样可以尽早在前端就禁止掉恶意的短地址。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

ddgghhjjkk 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1