Hi 游客

更多精彩,请登录!

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

. j) D  _9 x+ q; H% s第一参数是发送代币的目的地址,第二个参数是发送token的数量。1 a" [4 p% y& g7 @4 y* I
- w2 [0 j2 g1 `1 m
当我们调用transfer函数向某个地址发送N个ERC-20代币的时候,交易的input数据分为3个部分:* p0 R% V- F' h+ _) E- i

" s3 R7 Z9 }: f9 y; e+ Z4 字节,是方法名的哈希:a9059cbb6 r8 ?: z" Q) i7 ?; a. m" i$ V' t% A  z

$ f3 N! Y0 j5 T0 ^3 v3 z32字节,放以太坊地址,目前以太坊地址是20个字节,高危补0
% Z3 O% f5 D3 I) M
% E) \7 D6 v3 |$ v" Z000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca
  F# Z# W: n- P* t- q3 |
/ E7 @) I; [: k+ G' H+ m/ O32字节,是需要传输的代币数量,这里是1*10^18 GNT
! b; d0 ?9 ~3 U% P) j; g
) t- Z5 {& U  j; q+ T( w0000000000000000000000000000000000000000000000000de0b6b3a7640000" ?9 z, i7 z. v5 p5 @* W, M0 \0 t! }
1 [5 S4 T7 H/ D
所有这些加在一起就是交易数据:/ N! N5 t9 r' r$ ~& ]/ M& ^
& n- m8 X& y3 G5 e2 `% U/ [
a9059cbb000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca0000000000000000000000000000000000000000000000000de0b6b3a7640000
' g* b; E2 d' ?2 t- v% D9 c" e2 w8 ^+ n7 X3 [0 K# P
0x01 以太坊短地址6 Y. T4 P( V/ o% ]5 b4 v

; |2 g) h/ F* o) i! |$ e当调用transfer方法提币时,如果允许用户输入了一个短地址,这里通常是交易所这里没有做处理,比如没有校验用户输入的地址长度是否合法。/ N3 s. Z! \. T9 k

0 @7 i6 O$ C; P: N+ U+ u2 t如果一个以太坊地址如下,注意到结尾为0:" X' }  D3 }+ w5 u; S, y

6 P* o' P- b3 p2 q0x12345678901234567890123456789012345678008 }* Q! V3 \6 X: h6 G

2 `( x( a8 {  [当我们将后面的00省略时,EVM会从下一个参数的高位拿到00来补充,这就会导致一些问题了。' Q" O0 H' t( ]" t' u6 d

' n( x; E, o# D) B' e这时,token数量参数其实就会少了1个字节,即token数量左移了一个字节,使得合约多发送很多代币出来。我们看个例子:
! m2 b! e3 Z' w' |$ \4 ~$ I( K5 `8 m
; p: D6 z3 C0 K这里调用sendCoin方法时,传入的参数如下:% ^# B4 V* y" l. |$ `! P8 T* B
, I; H5 b0 V* S  c
0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb8644163e 0000000000000000000000000000000000000000000000000000000000000002
! m  C; P6 w5 a* ], B
; j" L  T! w& d/ V这里的0x90b98a11是method的hash值,第二个是地址,第三个是amount参数。
% {3 X+ ?$ E! C; n6 c! b; F) w1 @, R$ F
如果我们调用sendCoin方法的时候,传入地址0x62bec9abe373123b9b635b75608f94eb8644163e,把这个地址的“3e”丢掉,即扔掉末尾的一个字节,参数就变成了:5 {8 y5 Y0 _/ B% P6 ~( @3 N5 z- x
8 K* T$ }2 E, v6 E
0x90b98a11 00000000000000000000000062bec9abe373123b9b635b75608f94eb86441600 00000000000000000000000000000000000000000000000000000000000002                                                               ^^                              缺失1个字节* E+ C3 X& ~) b. E! x) C: @

9 G7 T( Y! {3 S. I- i这里EVM把amount的高位的一个字节的0填充到了address部分,这样使得amount向左移位了1个字节,即向左移位8。  J0 ?; \/ r: x. X2 t3 W  d, j, C
1 ~: z: b, L' f" \6 ^
这样,amount就成了2" A' `/ c' C$ G; p: d

% I0 O7 [% @( x& ]. ]0x02 构造短地址攻击
  W: n1 e6 W  w  O, H, {
- L% k$ S7 |  L' G2 V7 p4 M6 w(1)首先生成一个ETH的靓号,这个账号末尾为2个0$ |- }7 I+ m: \
; }+ B0 A  e8 o$ ?1 `, ]
使用一些跑号工具就可以做到,比如MyLinkToken工具,可以很轻易跑出末尾两个0的。
& X  D9 I7 J: G! U: z
3 m- F% w( x- x0 F, M, Q; o$ f(2)找一个交易所钱包,该钱包里token数量为256000; O1 v, T% w, y& G8 B
- G8 K! D; Y. s8 d5 b2 H' ~
(3)往这个钱包发送1000个币
0 x- i$ @4 }  {% s0 R
( c/ M, i7 N8 D+ I(4)然后再从这个钱包中提出1000个币,当然这时候写地址的时候把最后两个0去掉7 Y. ]8 {2 X  |
# n: \0 z; c$ p9 ]
如果交易所并没有校验用户填入的以太坊地址,则EVM会把所有函数的参数一起打包,会把amount参数的高位1个字节吃掉。8 X: ?0 P1 l3 g/ E2 O
' ^# h/ Y# J: w- d$ V
(5)这三个参数会被传入到msg.data中,然后调用合约的transfer方法,此时,amount由于高位的1个字节被吃掉了,因此amount = amount) O/ ]: n+ O5 G6 F5 L' e! z, p

! D8 P! d1 Q: F9 j$ V0x03 总结' n+ ]" ?( D; h1 C
9 i# m8 T4 d  u" X& e2 A" o6 X- J; S9 ]; l5 k
针对这个漏洞,说实话以太坊有不可推卸的责任,因为EVM并没有严格校验地址的位数,并且还擅自自动补充消失的位数。此外,交易所在提币的时候,需要严格校验用户输入的地址,这样可以尽早在前端就禁止掉恶意的短地址。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

ddgghhjjkk 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1