Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
EVM虚拟机在解析合约的字节码时,依赖的是ABI的定义,从而去识别各个字段位于字节码的什么地方。一般ERC-20 TOKEN标准的代币都会实现transfer方法,这个方法在ERC-20标签中的定义为:function transfer(address to, uint tokens) public returns (bool success);- y' D7 S7 v: R) Z1 q

, E, o. A7 @0 `. E第一参数是发送代币的目的地址,第二个参数是发送token的数量。
; E) [  Q( E- p8 L6 L  @1 s/ {! Y# {& {+ C  o0 D3 ?+ U+ J
当我们调用transfer函数向某个地址发送N个ERC-20代币的时候,交易的input数据分为3个部分:/ u' u% q8 G6 g" w# n* L+ C
1 W( P; \8 t0 j) H
4 字节,是方法名的哈希:a9059cbb$ t8 ^! s: M& \
$ T5 ~. a" J/ f. J' i
32字节,放以太坊地址,目前以太坊地址是20个字节,高危补0  S  H" D5 A$ G
& z2 G- U  n  \- {
000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca
5 v3 k0 q+ _! l/ M& z+ @* H- ^  D! A$ T! U6 V/ ]1 y1 g
32字节,是需要传输的代币数量,这里是1*10^18 GNT
( X$ _; b3 j" V6 Z; u% y' y
, j/ k( O! U" ?( ^1 i# z1 J0000000000000000000000000000000000000000000000000de0b6b3a7640000  D' \2 Z, z! |% r; G/ t

( ^$ ^" A$ e# V所有这些加在一起就是交易数据:
4 ?4 L2 r0 C* z2 l( {; g: @
* k4 \9 r% _5 O8 Z; ?* P& _7 N5 Na9059cbb000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca0000000000000000000000000000000000000000000000000de0b6b3a7640000
: h4 h7 x; A; L2 w% I" `! W& q3 c! e: [/ {, _0 A
0x01 以太坊短地址
/ w, c/ l+ n, y6 m+ F
4 T) P1 ?( X$ \当调用transfer方法提币时,如果允许用户输入了一个短地址,这里通常是交易所这里没有做处理,比如没有校验用户输入的地址长度是否合法。
* V7 u* y8 D. J2 g. g+ C
2 J- r7 [' e" e3 U9 x. d( J9 V/ d如果一个以太坊地址如下,注意到结尾为0:
6 o/ Y" z  `  y. \% f. M& C0 q- c. G# m8 C* L) b
0x1234567890123456789012345678901234567800% ?( K, P: l1 H

: c) R3 [. v5 U9 ]当我们将后面的00省略时,EVM会从下一个参数的高位拿到00来补充,这就会导致一些问题了。" f8 T1 K7 j! M$ C0 B# K2 n$ {
/ q. C, _/ l! `4 y8 z
这时,token数量参数其实就会少了1个字节,即token数量左移了一个字节,使得合约多发送很多代币出来。我们看个例子:
) g9 d3 A5 _. C1 Q! A
8 s. h+ ~6 k9 @- V这里调用sendCoin方法时,传入的参数如下:9 z; L  F% q! B/ Q) b. x

0 }" O! U6 J  S- u" N7 z( y0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb8644163e 00000000000000000000000000000000000000000000000000000000000000029 v" d# X* w. o, a. m  c8 \" T

" {1 y9 e  ?8 n7 x9 K. O/ d9 x这里的0x90b98a11是method的hash值,第二个是地址,第三个是amount参数。
+ v# F# ^7 P- k+ V& j: U
$ I$ B: X' z8 D* h6 p' J如果我们调用sendCoin方法的时候,传入地址0x62bec9abe373123b9b635b75608f94eb8644163e,把这个地址的“3e”丢掉,即扔掉末尾的一个字节,参数就变成了:$ |& B: H& z) Z) Q# B, O9 l$ d

( T5 V4 T7 s+ {: L/ Y3 R! l0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb86441600 00000000000000000000000000000000000000000000000000000000000002                                                               ^^                              缺失1个字节; l: f4 i! ~. [% w, N: w( z

7 N6 M  N& \0 [# O6 J% k这里EVM把amount的高位的一个字节的0填充到了address部分,这样使得amount向左移位了1个字节,即向左移位8。; G7 r* ~; V! j7 l. t+ s
7 h% b) @9 c3 d5 g* }( N! j
这样,amount就成了2
* R8 d$ X7 I4 t, ]+ R" G) ?8 S: m3 K1 U& q
0x02 构造短地址攻击
: \# d5 o2 Q4 K7 z8 \" ~: E6 f
. G: W( w3 e: X(1)首先生成一个ETH的靓号,这个账号末尾为2个0
2 M$ U% o! U- ]2 ?6 N+ h3 W" n( n! |
使用一些跑号工具就可以做到,比如MyLinkToken工具,可以很轻易跑出末尾两个0的。
  \6 o7 R9 p+ ~/ i6 O# w( u4 c
) Y, b0 x, t9 [1 e(2)找一个交易所钱包,该钱包里token数量为256000
  `1 t8 a, }: e- X
! _6 }9 i% s. \. o( m0 o(3)往这个钱包发送1000个币4 L% Q: O5 U# q9 }( ~

5 C9 D, v. V% _0 ?- ?(4)然后再从这个钱包中提出1000个币,当然这时候写地址的时候把最后两个0去掉4 H  _5 M8 h1 D( H- N$ P1 c
+ u% b7 ]. q8 x* o
如果交易所并没有校验用户填入的以太坊地址,则EVM会把所有函数的参数一起打包,会把amount参数的高位1个字节吃掉。/ F: P& m' v9 a* P: }/ f- c0 J, |3 R

3 I2 |( J( f' [. T1 k(5)这三个参数会被传入到msg.data中,然后调用合约的transfer方法,此时,amount由于高位的1个字节被吃掉了,因此amount = amount+ \7 b1 Z1 G5 \& _& c4 h' T8 D

# g% a+ H0 H- Y7 z. c0x03 总结( Y2 J1 Q# H" Y" l) U$ f

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

本版积分规则

成为第一个吐槽的人

ddgghhjjkk 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1