Hi 游客

更多精彩,请登录!

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

5 D8 Y. h. N' R% H7 Z- r: V第一参数是发送代币的目的地址,第二个参数是发送token的数量。
" W% v; s  _. n" G+ t3 l
/ d+ B% ?3 f8 O- S2 W: x4 O) V+ t当我们调用transfer函数向某个地址发送N个ERC-20代币的时候,交易的input数据分为3个部分:
+ z, d1 ^) y: V7 S+ v% O- c" V% F# y8 A5 t/ S
4 字节,是方法名的哈希:a9059cbb
. X, K7 {- u* n2 A% J9 Y
( Z$ ~/ ~6 a6 O9 @, E32字节,放以太坊地址,目前以太坊地址是20个字节,高危补0
5 r5 L% b# X3 I7 f) p7 a+ ~) S. h8 x
000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca, O2 O8 ~1 [, d4 p0 d
4 o' D0 G) e' P$ @- _" B2 [0 R
32字节,是需要传输的代币数量,这里是1*10^18 GNT
# S* o, M6 p! b: X: [2 I5 M+ w- E1 z, z" n/ M
0000000000000000000000000000000000000000000000000de0b6b3a7640000
6 D6 P  y) {1 f' t# t  J
" _5 T0 `1 F) h+ _1 O6 A所有这些加在一起就是交易数据:
) R, G2 i: \, d4 t$ G; W4 g* d
! z9 V9 Q+ J$ B' k4 Xa9059cbb000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca0000000000000000000000000000000000000000000000000de0b6b3a7640000
7 y! T: j+ U9 _  g3 U; h4 b. |3 \2 h4 V  v( _
0x01 以太坊短地址
, b  z* [' O8 g8 d: K) e; A% B# s9 a5 |% E) R
当调用transfer方法提币时,如果允许用户输入了一个短地址,这里通常是交易所这里没有做处理,比如没有校验用户输入的地址长度是否合法。( N- F$ W8 Q. F1 H3 ^! \- n
+ J; V# d2 v. S
如果一个以太坊地址如下,注意到结尾为0:
( d  ?- A/ G9 p! e3 U. I7 N% F' q1 U3 f- g: t# s% |  x
0x1234567890123456789012345678901234567800
/ f$ s8 D' x6 w0 v
. P( k0 j1 @3 }/ O当我们将后面的00省略时,EVM会从下一个参数的高位拿到00来补充,这就会导致一些问题了。( x; u7 Y! Y7 d2 N
& w# B1 |  x. t3 K; J& R# d
这时,token数量参数其实就会少了1个字节,即token数量左移了一个字节,使得合约多发送很多代币出来。我们看个例子:( V. J* p4 M6 p2 d
- E; _; X5 J& e" v$ C- w# b
这里调用sendCoin方法时,传入的参数如下:
, p" H+ n9 U7 e! ?0 z2 b# P. s) d9 Z2 `
0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb8644163e 0000000000000000000000000000000000000000000000000000000000000002
" A6 [. h6 |& b7 ?: T" q+ R' m$ K' l, I
这里的0x90b98a11是method的hash值,第二个是地址,第三个是amount参数。, f9 u& i" v( l; }: R

; ^+ V/ [. L" l# i, `1 |: U如果我们调用sendCoin方法的时候,传入地址0x62bec9abe373123b9b635b75608f94eb8644163e,把这个地址的“3e”丢掉,即扔掉末尾的一个字节,参数就变成了:' `" d/ f2 e! d5 q1 z

( j- \. G% f! w- L" t' D& S8 m0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb86441600 00000000000000000000000000000000000000000000000000000000000002                                                               ^^                              缺失1个字节
% A( l9 W: L; [4 h* v4 z6 Y9 V3 u2 a% P1 p' }* T) u+ f6 N9 z5 C2 ^
这里EVM把amount的高位的一个字节的0填充到了address部分,这样使得amount向左移位了1个字节,即向左移位8。
; I4 H2 `( c' B& b
: o( h) g4 ?; X5 w& d8 `8 n8 M' W这样,amount就成了2
6 z& i- N$ l& X; ?8 F7 o9 q8 b" \9 @6 t
0x02 构造短地址攻击
$ F! H- D: n; _' j
% Y$ i+ Z* m2 p+ }(1)首先生成一个ETH的靓号,这个账号末尾为2个0
' V9 I7 c9 p% `/ \
! r0 y( Z+ K/ ?6 m' ?& P) X使用一些跑号工具就可以做到,比如MyLinkToken工具,可以很轻易跑出末尾两个0的。
% r8 W4 O: w9 J
2 F) `5 A6 {1 b2 M% u6 r$ K; L(2)找一个交易所钱包,该钱包里token数量为256000
8 }# z$ f% m" |% _6 H0 y# [
- X% ?- i5 b# r  e: S" @: v1 H(3)往这个钱包发送1000个币
7 b1 R  V8 `9 N+ o( w. x$ Q3 Y
" ?( C" ?$ h5 m3 ?& x(4)然后再从这个钱包中提出1000个币,当然这时候写地址的时候把最后两个0去掉
7 _! O  T+ Z- I0 u9 I. O: [: I' G! M( X1 p! `
如果交易所并没有校验用户填入的以太坊地址,则EVM会把所有函数的参数一起打包,会把amount参数的高位1个字节吃掉。& \* S3 B; A/ V6 n9 V. d

! k& N" H6 p: l  f: D# E3 N. n(5)这三个参数会被传入到msg.data中,然后调用合约的transfer方法,此时,amount由于高位的1个字节被吃掉了,因此amount = amount, _- U% w) u* o( B
' w9 B! J, ]5 {* n
0x03 总结
' ^: D: H  \- V! W0 M; |" ?, \, }: U' d' G( w) \$ ^2 f
针对这个漏洞,说实话以太坊有不可推卸的责任,因为EVM并没有严格校验地址的位数,并且还擅自自动补充消失的位数。此外,交易所在提币的时候,需要严格校验用户输入的地址,这样可以尽早在前端就禁止掉恶意的短地址。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

ddgghhjjkk 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1