Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
EVM虚拟机在解析合约的字节码时,依赖的是ABI的定义,从而去识别各个字段位于字节码的什么地方。一般ERC-20 TOKEN标准的代币都会实现transfer方法,这个方法在ERC-20标签中的定义为:function transfer(address to, uint tokens) public returns (bool success);1 L& P2 \9 Z8 t" R4 l
& W3 M3 y3 m7 @5 ?
第一参数是发送代币的目的地址,第二个参数是发送token的数量。
: {( A1 @4 i# ^8 O4 o! [
+ w/ P% P& x  [- V) M  d7 G/ m, W当我们调用transfer函数向某个地址发送N个ERC-20代币的时候,交易的input数据分为3个部分:9 w7 L  \4 d  M/ C: J

2 ?* J. K) R2 L4 字节,是方法名的哈希:a9059cbb
& w" d( m) |4 m* l" 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

  S6 P8 n( z# C+ X5 e8 d32字节,是需要传输的代币数量,这里是1*10^18 GNT, k7 N' ?8 {# z6 Q

" t5 N( I1 g8 n! V. P" v4 ~0000000000000000000000000000000000000000000000000de0b6b3a7640000
8 F4 i9 _5 W7 e0 Z- N; q0 H
7 }8 Q. a3 L  _- t, d: g  w& I所有这些加在一起就是交易数据:' e5 h4 c$ \, }9 Z( B, [2 g
) \. A9 S% `* s3 y
a9059cbb000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca0000000000000000000000000000000000000000000000000de0b6b3a7640000
" M% k) ^) W4 h! f. T+ A2 P  x. }! o' H- ?
0x01 以太坊短地址
+ u# o0 q7 G* S& D
# x, y5 F- Y3 r4 p当调用transfer方法提币时,如果允许用户输入了一个短地址,这里通常是交易所这里没有做处理,比如没有校验用户输入的地址长度是否合法。( @) R0 N, P+ e4 T0 a( K
1 F" v  P2 e5 ]  g/ r5 g/ p
如果一个以太坊地址如下,注意到结尾为0:
& A! \" h+ k2 [( [5 I% h* {- L
$ Z3 I3 _2 `% `5 E8 A0x1234567890123456789012345678901234567800
6 z1 G2 i6 O  C" P& i$ |
, Q, G* I0 \( q% |- t6 q当我们将后面的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" `

7 F2 {8 a" V2 h2 e' ]" T这里调用sendCoin方法时,传入的参数如下:
4 O. n; |$ }& _- d; w5 [$ `
6 Q4 i4 Q: g7 d. {2 w! K( d0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb8644163e 0000000000000000000000000000000000000000000000000000000000000002
( H/ I. W  u( w, T( m9 L
0 X) s9 H  f4 S这里的0x90b98a11是method的hash值,第二个是地址,第三个是amount参数。
# \& S. Y- v* d9 \5 F
3 B. a4 c3 E/ D3 R如果我们调用sendCoin方法的时候,传入地址0x62bec9abe373123b9b635b75608f94eb8644163e,把这个地址的“3e”丢掉,即扔掉末尾的一个字节,参数就变成了:+ T3 N; `7 N* ^+ J0 W7 H: j

# V  f& P8 e- z& Y0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb86441600 00000000000000000000000000000000000000000000000000000000000002                                                               ^^                              缺失1个字节! e% g( A1 f7 V' a4 P' v

$ `% @1 c5 j& `. T这里EVM把amount的高位的一个字节的0填充到了address部分,这样使得amount向左移位了1个字节,即向左移位8。
: S/ R% G8 ]* p0 @2 G& {
- ]5 [# s# D( t7 P* E这样,amount就成了2$ V: ]4 }3 k- v
& u; y& c0 Y7 m: Y4 j
0x02 构造短地址攻击  o; o+ F7 c/ U9 j, p9 ^

! l+ r( K' Z; g& s5 \6 e, z7 \(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个字节吃掉。
9 Z4 S. l* Y6 ?! p  y) [& 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 总结
. J: ]9 _/ K# T! j
% c( x7 }0 U1 \  a' l4 j/ D针对这个漏洞,说实话以太坊有不可推卸的责任,因为EVM并没有严格校验地址的位数,并且还擅自自动补充消失的位数。此外,交易所在提币的时候,需要严格校验用户输入的地址,这样可以尽早在前端就禁止掉恶意的短地址。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

ddgghhjjkk 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1