Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
EVM虚拟机在解析合约的字节码时,依赖的是ABI的定义,从而去识别各个字段位于字节码的什么地方。一般ERC-20 TOKEN标准的代币都会实现transfer方法,这个方法在ERC-20标签中的定义为:function transfer(address to, uint tokens) public returns (bool success);
/ x3 `7 K. c  {/ ]( Q, K6 F$ s
3 ?" H) y' j4 o: F1 L第一参数是发送代币的目的地址,第二个参数是发送token的数量。2 A: c) G% H. h
+ I4 M( M! E- u. h1 A# f9 x
当我们调用transfer函数向某个地址发送N个ERC-20代币的时候,交易的input数据分为3个部分:! W2 D3 ]5 A& }) L2 m

  A7 O+ p6 f7 R& N9 _; l8 f; y4 字节,是方法名的哈希:a9059cbb) y2 G. G  ~& t, B, P3 j0 Y

6 w- l2 _! u3 G32字节,放以太坊地址,目前以太坊地址是20个字节,高危补0
7 t, E4 Q) o+ B7 q7 A  M- W* ^. ^; D7 N* g* ?
000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca
- x' _- N" _6 z, r5 q, `8 v" H1 B% H2 N/ b, m7 P, [, T
32字节,是需要传输的代币数量,这里是1*10^18 GNT; ~& i7 c. k1 n4 z( M' Q

$ X; W% z/ m" ^0000000000000000000000000000000000000000000000000de0b6b3a7640000! ^+ q* F. e1 ^" E. }% b' C9 |* }5 J0 d' A
' {8 }, k! v3 A; ~  x1 Q( X
所有这些加在一起就是交易数据:2 s# V( H7 ]5 G8 J; X$ H" W
# @- \5 ~: Z& d# F& e8 c
a9059cbb000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca0000000000000000000000000000000000000000000000000de0b6b3a7640000
% c; W" r( a) z2 Y0 d, H$ G! o, P* x
0x01 以太坊短地址
" i& g; F% z% R3 T: u9 y
- v0 e: J, I1 i7 a3 J当调用transfer方法提币时,如果允许用户输入了一个短地址,这里通常是交易所这里没有做处理,比如没有校验用户输入的地址长度是否合法。
$ p' \" h) L0 E/ g2 b' T* T2 w. w6 J' q2 o8 b' w' R9 Y
如果一个以太坊地址如下,注意到结尾为0:
3 m! _8 H% `# \6 @+ m" c/ B7 I. T$ w8 k" T
0x1234567890123456789012345678901234567800
4 R6 e& n$ \: O) D! D0 y; a6 |9 F6 }, F5 S
当我们将后面的00省略时,EVM会从下一个参数的高位拿到00来补充,这就会导致一些问题了。9 V1 f; Y: m: O

! A, s5 V& `8 V+ z5 O% a这时,token数量参数其实就会少了1个字节,即token数量左移了一个字节,使得合约多发送很多代币出来。我们看个例子:! x% G# Q& O6 }* b
" _. k) r+ h5 }/ G1 Y
这里调用sendCoin方法时,传入的参数如下:
( T! P7 P; J/ C' T; M2 O  e: W' w5 z/ k5 `* M
6 o4 i# Q4 j- K  h& }, H  [8 L. O0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb8644163e 00000000000000000000000000000000000000000000000000000000000000028 t- \3 `. b! t# t. K
8 z& [# V  r2 f% L1 x, R5 v* w
这里的0x90b98a11是method的hash值,第二个是地址,第三个是amount参数。, d' ~" I: k; ^1 \2 A
+ M/ m2 J- ^3 q& H4 k
如果我们调用sendCoin方法的时候,传入地址0x62bec9abe373123b9b635b75608f94eb8644163e,把这个地址的“3e”丢掉,即扔掉末尾的一个字节,参数就变成了:- v8 j/ V" M! N7 \1 X* |
! ^& q+ x- T% L8 o, X& l
0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb86441600 00000000000000000000000000000000000000000000000000000000000002                                                               ^^                              缺失1个字节/ s( D6 ^8 k& @3 _. v

) ]2 U4 b8 @0 r, ]- Y. B这里EVM把amount的高位的一个字节的0填充到了address部分,这样使得amount向左移位了1个字节,即向左移位8。2 j/ S4 r$ |7 }) e/ N
# l6 \$ F3 U8 i7 a' A
这样,amount就成了2; ~) Z$ N, _/ e$ \. }7 L9 Y: O
5 [0 {, ~+ [9 {9 Q1 q- t2 g+ c
0x02 构造短地址攻击$ c- b' f3 K. @/ u4 d3 N3 C8 w  f
) F& {: v* t6 {
(1)首先生成一个ETH的靓号,这个账号末尾为2个05 {  ]$ c8 F" ?4 Z9 }
- U; T) ?# H0 i
使用一些跑号工具就可以做到,比如MyLinkToken工具,可以很轻易跑出末尾两个0的。' c: N5 Q- L' f+ r  O" l

9 R( \4 v0 M- F6 p# d/ A" ~" }$ a" i(2)找一个交易所钱包,该钱包里token数量为2560008 a& x+ C. A9 R; I1 s

* g1 L9 n6 \8 k$ V9 `- L& W(3)往这个钱包发送1000个币7 x7 R* i$ h. ?' h1 E

! x# @9 Y6 t: F) e) i1 o(4)然后再从这个钱包中提出1000个币,当然这时候写地址的时候把最后两个0去掉3 Y- ?( ~+ {( m' b6 o
5 n- N, U$ s6 a% ]
如果交易所并没有校验用户填入的以太坊地址,则EVM会把所有函数的参数一起打包,会把amount参数的高位1个字节吃掉。/ p& K+ v9 ?* l; D. `0 g. P% i- T# \0 R
+ i5 O7 N, {  R8 w
(5)这三个参数会被传入到msg.data中,然后调用合约的transfer方法,此时,amount由于高位的1个字节被吃掉了,因此amount = amount
" K8 u2 X& @) O9 `* Z6 M- u# o+ G9 E
0x03 总结3 W% o# z; }# T5 P2 P

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

本版积分规则

成为第一个吐槽的人

ddgghhjjkk 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1