Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文
EVM虚拟机在解析合约的字节码时,依赖的是ABI的定义,从而去识别各个字段位于字节码的什么地方。一般ERC-20 TOKEN标准的代币都会实现transfer方法,这个方法在ERC-20标签中的定义为:function transfer(address to, uint tokens) public returns (bool success);
' C2 p' r9 v0 C
  O( o2 G" @. L6 x. R第一参数是发送代币的目的地址,第二个参数是发送token的数量。& M0 Q) t. ?$ S% ]& W2 B

6 G. T+ ~1 @* M当我们调用transfer函数向某个地址发送N个ERC-20代币的时候,交易的input数据分为3个部分:
9 ^0 T# _% M* f; g. V- k4 V- S9 d2 x: Z: G2 O
4 字节,是方法名的哈希:a9059cbb
# l' h9 U4 j* R  e! R) e  J2 s( w/ w2 w2 B
32字节,放以太坊地址,目前以太坊地址是20个字节,高危补0! a& j5 z# |, o2 w+ b
% V# I. q- o' L& B- G6 i1 p* e$ Q
000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca# D/ }4 \% c' e: f8 L0 C- f, W

+ S+ T% o7 t2 \9 i9 m32字节,是需要传输的代币数量,这里是1*10^18 GNT
* O+ G0 b/ E4 H& }
- d& T/ {! B2 r! o- W6 Y) ?  P% z) [6 T0000000000000000000000000000000000000000000000000de0b6b3a7640000
7 n9 u  f9 R' W! F& I1 ^# B; R8 i9 }" q' C
所有这些加在一起就是交易数据:
* r! W/ |9 \3 \& s
4 m. J6 @4 m! b8 I+ b* La9059cbb000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca0000000000000000000000000000000000000000000000000de0b6b3a7640000" s% T8 x2 Y' W+ s1 |. Z2 T( u8 S' o
& p3 c/ ^* q7 l2 p7 J/ X3 B
0x01 以太坊短地址0 S# ?9 r$ S2 V  L$ H6 Y) C
9 y% {" [/ T5 J
当调用transfer方法提币时,如果允许用户输入了一个短地址,这里通常是交易所这里没有做处理,比如没有校验用户输入的地址长度是否合法。
; R( {6 u6 {3 D3 g' V
0 h! v+ B2 t; [9 q如果一个以太坊地址如下,注意到结尾为0:
) F. M1 H& T9 v3 k. `+ D
1 |. f- q) _3 B0x12345678901234567890123456789012345678006 X, r3 v4 D0 w) b2 Q  a% p: K
6 T# V% X/ g  G2 R: ^% [
当我们将后面的00省略时,EVM会从下一个参数的高位拿到00来补充,这就会导致一些问题了。
  r. e0 f" z9 ^3 k* M- K, U* ^/ p3 {: [: g$ V
这时,token数量参数其实就会少了1个字节,即token数量左移了一个字节,使得合约多发送很多代币出来。我们看个例子:
" j, U2 _2 c& L7 C: n/ I- V  O( @% Y+ N+ z- T' }
这里调用sendCoin方法时,传入的参数如下:
, e0 b' }5 \3 \) H1 w8 B8 U. Z5 {& i& r; `" |! U- J; w. Y. g6 N  K% C
0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb8644163e 0000000000000000000000000000000000000000000000000000000000000002
7 S  E; H: R# Z: @$ o5 q: Y. l3 W- ?: Y- w
这里的0x90b98a11是method的hash值,第二个是地址,第三个是amount参数。4 V% T2 L% l1 ], g4 ^. \( p9 ?# k4 y

$ ^+ j; q: p, s, L- t如果我们调用sendCoin方法的时候,传入地址0x62bec9abe373123b9b635b75608f94eb8644163e,把这个地址的“3e”丢掉,即扔掉末尾的一个字节,参数就变成了:
8 T2 ~( Y" {# P/ ]& R8 Z. I
  _* S4 Y6 I$ b% l0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb86441600 00000000000000000000000000000000000000000000000000000000000002                                                               ^^                              缺失1个字节
2 F3 O8 M0 Z5 Z! X8 L  O
% L: O9 T3 q  \: Z, F( Y8 t' Z: `2 D这里EVM把amount的高位的一个字节的0填充到了address部分,这样使得amount向左移位了1个字节,即向左移位8。
: W* b9 p3 i, B  W/ K5 U1 l
& Q; r- U. `4 j0 |0 k9 j这样,amount就成了2
1 l6 D7 `; m4 x7 K( f: n* E/ Q3 C0 `: J# O
0x02 构造短地址攻击
$ U0 X; S' U& X6 _& \& u+ W$ ?6 x' }3 ?) n' d" Y
(1)首先生成一个ETH的靓号,这个账号末尾为2个0
8 I/ \, [' l+ H1 Q$ n* I. M
/ R. N) H5 b/ m  s0 K& X使用一些跑号工具就可以做到,比如MyLinkToken工具,可以很轻易跑出末尾两个0的。
5 W, a1 _. U: L  T, S6 _- W
" L* n* v3 n% J) L(2)找一个交易所钱包,该钱包里token数量为256000/ ~( ^) t8 Z7 C) R" S, {
& K8 I; A% w; L( n/ r1 x$ o7 W
(3)往这个钱包发送1000个币
! V. a; [6 L# l, ?% \9 e' \! k, ~8 n1 u9 N3 K
(4)然后再从这个钱包中提出1000个币,当然这时候写地址的时候把最后两个0去掉
7 ^3 S0 i$ O% j# T" m8 {/ D. a; [0 L7 {+ X: a  N0 o4 Z& ~' I! w: N
如果交易所并没有校验用户填入的以太坊地址,则EVM会把所有函数的参数一起打包,会把amount参数的高位1个字节吃掉。
/ j' ]9 |; K' \$ a. a6 n
6 M% c- D+ P, @: q6 X0 E(5)这三个参数会被传入到msg.data中,然后调用合约的transfer方法,此时,amount由于高位的1个字节被吃掉了,因此amount = amount/ @% j4 o6 \, @* L1 R2 V
5 Q: g& Z  W! ~9 g+ `
0x03 总结0 }+ k. b  K% ~2 n
7 w1 i! h, O/ h
针对这个漏洞,说实话以太坊有不可推卸的责任,因为EVM并没有严格校验地址的位数,并且还擅自自动补充消失的位数。此外,交易所在提币的时候,需要严格校验用户输入的地址,这样可以尽早在前端就禁止掉恶意的短地址。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

ddgghhjjkk 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1