Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
EVM虚拟机在解析合约的字节码时,依赖的是ABI的定义,从而去识别各个字段位于字节码的什么地方。一般ERC-20 TOKEN标准的代币都会实现transfer方法,这个方法在ERC-20标签中的定义为:function transfer(address to, uint tokens) public returns (bool success);
- n$ w0 Y: y2 U* y9 C1 I4 ~1 `/ Y1 |, h
第一参数是发送代币的目的地址,第二个参数是发送token的数量。
- `; d* c# r3 r
0 w9 Z3 S8 E' N  L& H2 ?2 U当我们调用transfer函数向某个地址发送N个ERC-20代币的时候,交易的input数据分为3个部分:
; v+ c* O- G/ k8 N: K: A
) ^3 i/ e  m" O( J/ O* E4 字节,是方法名的哈希:a9059cbb9 r; Y: k. z3 F: |) ^9 j

8 C; ?6 ?8 ]8 `32字节,放以太坊地址,目前以太坊地址是20个字节,高危补0
" m  N3 `7 w& K$ v9 z) @
0 A, S7 w0 C1 B4 P. i6 z- m: w" ]000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca
( |7 b5 o% I, t( q; s- L
/ S! Q+ Z( h3 {32字节,是需要传输的代币数量,这里是1*10^18 GNT
: {( Z% `3 G& T* H, l2 s2 `: ?! v5 A- s8 D  U  T
0000000000000000000000000000000000000000000000000de0b6b3a7640000
# c  C. k$ u! x# R% n
/ E' \4 o' i; }# u/ O' g所有这些加在一起就是交易数据:
2 U  o. \4 t* \2 q9 a  W# R5 g# r( l% F' E# u5 m
a9059cbb000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca0000000000000000000000000000000000000000000000000de0b6b3a7640000
0 p) M! U$ P0 Z# W7 z3 U
; a4 d  E; m: {( V0x01 以太坊短地址' ^1 S9 j' l3 ?8 I! \  ~3 C
1 g( V" J$ C# O1 X, H
当调用transfer方法提币时,如果允许用户输入了一个短地址,这里通常是交易所这里没有做处理,比如没有校验用户输入的地址长度是否合法。
& h  _8 M5 J* Z& @3 N# P0 _$ \, d1 W/ Y' r9 O
如果一个以太坊地址如下,注意到结尾为0:9 \' z( R; v. ]' M7 n6 j
7 h4 j/ R. v- T, V0 H% N
0x12345678901234567890123456789012345678001 ?, {$ o% t' N( i5 d  `" }

- G4 A6 t) U( Y6 z当我们将后面的00省略时,EVM会从下一个参数的高位拿到00来补充,这就会导致一些问题了。* P; i1 i/ h/ i3 X' Y$ H; g
! ~0 x) q. C! y* t: t+ ^" s; l
这时,token数量参数其实就会少了1个字节,即token数量左移了一个字节,使得合约多发送很多代币出来。我们看个例子:9 O- \: F+ R4 V5 F4 {6 Z

1 a- _# g. H% j- Z1 g这里调用sendCoin方法时,传入的参数如下:6 N5 R' J" b' w( q5 p3 G5 i

+ p; h6 D- e3 c4 p0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb8644163e 0000000000000000000000000000000000000000000000000000000000000002
1 _* c/ e; N$ `0 g1 v: Z/ Y4 [2 O, D2 N
这里的0x90b98a11是method的hash值,第二个是地址,第三个是amount参数。
6 @! G7 T. [$ B$ Q% m& i2 x% Z! c% o6 }6 p
如果我们调用sendCoin方法的时候,传入地址0x62bec9abe373123b9b635b75608f94eb8644163e,把这个地址的“3e”丢掉,即扔掉末尾的一个字节,参数就变成了:- c- M( x0 O* W! b- s
7 @, m3 [( K. E/ L
0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb86441600 00000000000000000000000000000000000000000000000000000000000002                                                               ^^                              缺失1个字节
! u% U2 G& B3 ^. @( [1 l
! c; M+ R. ^) K1 q5 e% R这里EVM把amount的高位的一个字节的0填充到了address部分,这样使得amount向左移位了1个字节,即向左移位8。
* Z  d9 u  ^; J! j* i4 R: _6 Z0 ^  s, Q! h- g  {2 h! e( C7 E% f
这样,amount就成了2
# G1 o, {/ B( K! N) m8 R, m6 }9 b, C
0x02 构造短地址攻击% N, }; S) R( v4 e* t* o
( ^, v7 E6 M" u9 A8 b1 N, h  F
(1)首先生成一个ETH的靓号,这个账号末尾为2个0
9 U& T/ C4 k# P/ X
4 U1 L5 C7 |: d3 C+ x使用一些跑号工具就可以做到,比如MyLinkToken工具,可以很轻易跑出末尾两个0的。
' a* V& y) M( N
' K5 }0 A5 P" X# f9 x- J# X(2)找一个交易所钱包,该钱包里token数量为256000' V& g$ U8 \. W9 [/ c7 F
" K/ f+ s: U9 H
(3)往这个钱包发送1000个币" G1 \. l8 u+ ]! P% z. N$ [- z% K* Y

3 }% A/ _7 b5 `# r(4)然后再从这个钱包中提出1000个币,当然这时候写地址的时候把最后两个0去掉
7 {! M5 L* ]! M) i: W1 E
, H, c) Z$ F6 b% G5 W9 D如果交易所并没有校验用户填入的以太坊地址,则EVM会把所有函数的参数一起打包,会把amount参数的高位1个字节吃掉。# I+ N$ o; U, V) u' U2 O
" m1 s4 d+ F8 t- o! k, F, ~
(5)这三个参数会被传入到msg.data中,然后调用合约的transfer方法,此时,amount由于高位的1个字节被吃掉了,因此amount = amount0 p3 ]1 t% Q* V' }/ x$ g
: U& }% c9 F. W: d/ P' I  G7 G4 \! B9 R
0x03 总结: s/ _0 s  w' N5 b( A: A

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

本版积分规则

成为第一个吐槽的人

ddgghhjjkk 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1