Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
EVM虚拟机在解析合约的字节码时,依赖的是ABI的定义,从而去识别各个字段位于字节码的什么地方。一般ERC-20 TOKEN标准的代币都会实现transfer方法,这个方法在ERC-20标签中的定义为:function transfer(address to, uint tokens) public returns (bool success);
2 p0 U1 D) f, L; u8 [3 g3 H0 n7 M* e
第一参数是发送代币的目的地址,第二个参数是发送token的数量。
) y2 \# E1 t) p+ v. g: S9 ^5 S
: u& T. a* M3 S8 C: m- ^+ a& L当我们调用transfer函数向某个地址发送N个ERC-20代币的时候,交易的input数据分为3个部分:
+ Z  n' ^/ ?8 h4 o. P7 d3 ]: x1 f. C6 D( s* m) `  B
4 字节,是方法名的哈希:a9059cbb
* k# v2 K* T3 s; L
4 G5 N$ q' x% k/ A& Y1 t6 \! n32字节,放以太坊地址,目前以太坊地址是20个字节,高危补03 P% t. N+ E2 I) @& n

0 x1 e1 a0 `2 T* T  B0 [% `000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca
, Z; ]* G1 P' c! l, g% U5 |8 _; \4 f- I5 v' }! x
32字节,是需要传输的代币数量,这里是1*10^18 GNT
( j- p5 a$ t  q' J
; Y  @3 x( t$ w+ ~# }. e( a/ A0000000000000000000000000000000000000000000000000de0b6b3a7640000
6 C' A5 G2 ~$ g4 a! p# u+ L3 R3 |7 p$ f  [' q5 N2 O. X* x5 G
所有这些加在一起就是交易数据:
/ h. U; e  w& K4 a1 v  O  P# s$ M- \) k% W
a9059cbb000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca0000000000000000000000000000000000000000000000000de0b6b3a7640000
) C9 o) _- ]0 M! R% o
6 m, {9 f7 i$ f0x01 以太坊短地址
7 j7 C6 W$ d$ k; c: f! X1 _' r! O9 `, q
当调用transfer方法提币时,如果允许用户输入了一个短地址,这里通常是交易所这里没有做处理,比如没有校验用户输入的地址长度是否合法。/ A) F7 X2 r4 s- {* ]! H. U

/ G- \4 J2 p( ]* L如果一个以太坊地址如下,注意到结尾为0:  ]0 _3 |) \0 z3 q; ~
) ^* Q% ^' o+ w
0x12345678901234567890123456789012345678006 |; D1 I# K2 C: \
7 L3 s8 |4 h9 H; T# K0 V% J& y& y
当我们将后面的00省略时,EVM会从下一个参数的高位拿到00来补充,这就会导致一些问题了。6 K, {2 u: L  n( s# g( U9 B$ H
8 W/ S0 n- N0 |7 S* _( V, X
这时,token数量参数其实就会少了1个字节,即token数量左移了一个字节,使得合约多发送很多代币出来。我们看个例子:
8 a/ y% v6 [- N! L1 c$ p+ ]* j
% V6 S' a8 P9 @% u+ n( \) y- H$ K这里调用sendCoin方法时,传入的参数如下:
8 O; ^+ t+ f  U& \, n( p8 R' Q# X
5 g5 u! D4 t- q0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb8644163e 0000000000000000000000000000000000000000000000000000000000000002
' F- O5 Z% x1 Y; O2 |" q' D% O; H* z) [' O  N: j! k( s5 o4 p
这里的0x90b98a11是method的hash值,第二个是地址,第三个是amount参数。- R6 }3 [  o; ]8 y

6 Y0 n7 R8 |. p7 ^. R1 T. B如果我们调用sendCoin方法的时候,传入地址0x62bec9abe373123b9b635b75608f94eb8644163e,把这个地址的“3e”丢掉,即扔掉末尾的一个字节,参数就变成了:
( Z4 B3 T) I3 u( k$ k8 j; v/ a
: |, f* G: B- X2 V0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb86441600 00000000000000000000000000000000000000000000000000000000000002                                                               ^^                              缺失1个字节
8 ^$ y4 A' x8 m4 P/ I% X; h" |; V6 x) Q& \- f8 C* u5 u) e
这里EVM把amount的高位的一个字节的0填充到了address部分,这样使得amount向左移位了1个字节,即向左移位8。
! U9 L! d3 v& ~0 j0 y
& V$ A- M; V  n2 W8 ?$ w" |这样,amount就成了2, _9 s# ^; r: `  ]9 p
5 |7 ^' S$ d) c) W) B4 n9 x
0x02 构造短地址攻击5 q3 U: w8 V: V' K3 v2 J

3 G  M0 E+ v/ {  T4 y" h) u' y(1)首先生成一个ETH的靓号,这个账号末尾为2个0
# d: l' _, l, o) w; j" e  v
# N, w! c+ k; A: u使用一些跑号工具就可以做到,比如MyLinkToken工具,可以很轻易跑出末尾两个0的。
9 T8 r" e; T6 R' k% U" ~0 x$ h( I0 q6 u4 Q' V( u
(2)找一个交易所钱包,该钱包里token数量为256000" V( _8 h$ H# F2 k2 H; a( o
. M+ q3 L0 t% m1 p5 ^: }; I# ]
(3)往这个钱包发送1000个币
/ {0 a3 \5 u* n3 S* I% X4 n
; D& @! z" ?* C  B(4)然后再从这个钱包中提出1000个币,当然这时候写地址的时候把最后两个0去掉- N& }( Y; c  z& h) @0 p# k
9 _$ K  ]2 q0 I  T  J/ F8 Q
如果交易所并没有校验用户填入的以太坊地址,则EVM会把所有函数的参数一起打包,会把amount参数的高位1个字节吃掉。! q/ n2 d; h9 X, z. P  ~
" e* |( l9 u7 T8 m, s
(5)这三个参数会被传入到msg.data中,然后调用合约的transfer方法,此时,amount由于高位的1个字节被吃掉了,因此amount = amount, C: _8 n" d( W$ L0 _% o7 F; S- R; P0 G
! \$ K' z& c  _6 a) L! D3 e
0x03 总结
5 J; Z9 L, S) \+ Q6 M/ W; |" z, F; W7 r5 }# k2 F
针对这个漏洞,说实话以太坊有不可推卸的责任,因为EVM并没有严格校验地址的位数,并且还擅自自动补充消失的位数。此外,交易所在提币的时候,需要严格校验用户输入的地址,这样可以尽早在前端就禁止掉恶意的短地址。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

ddgghhjjkk 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1