JavaScript 不可用。

我们检测到浏览器禁用了 JavaScript。请启用 JavaScript 或改用支持的浏览器来继续访问

一种可能的地址参数攻击方式,或许发生在桥/交易所 [短地址攻击]

作者:Anban Chu

发表日期:2018年06月05日

所属目录:黑客攻击

场景描述

短地址攻击(Short Address Attack)利用的是 EVM 中的对于输入字节码的自动补全机制进行攻击。

  • 正常的地址格式: 0xf8905f04bde033c0a797a90ce30a8e157b3614d0
  • EVM 内可以省略为: 0xf8905f04bde033c0a797a90ce30a8e157b3614d

直接在用户界面操作,会提示错误。需要走原始交易发送才可以。

ERC20 合约中的 transfer(address,uint256) 输入的字节码位数都是 136 字节的。比如向地址 0xf8905f04bde033c0a797a90ce30a8e157b3614d090000000000000000

0xa9059cbb  // 8位
000000000000000000000000f8905f04bde033c0a797a90ce30a8e157b3614d0    // 64 位
000000000000000000000000000000000000000000000000013fbe85edc90000    // 64 位

当调用 ERC20 中的 transfer 函数进行 ERC20 Token 转账时,如果攻击者提供的地址后有一个或多个 0,那么攻击者就可以把地址后的零省去,提供一个缺位的地址。

根据 EVM 解析器,这个调用的规定其实是如下的(客户端来满足)。

  • 开头 4 字节是函数签名。
  • 中间 32 字节是 address _to(转账的目标地址),不足,则高位补 0。
  • 末尾 32 字节是 uint256 _value(转账金额),不足,则高位补 0。

在这种情况下,EVM 就会对缺失的字节位在编码数据的末尾进行补 0 凑成 136 字节,这样本来地址段缺失的 0 被数据段的 0 补齐了,而由于给地址段补 0,数据段会少 0,而数据段缺失的 0 由 EVM 自动补齐,这就像数据段向地址段移动补齐地址段缺失字节位,然后数据段缺失的字节位由 EVM 用 0 补齐。

0xa9059cbb  // 8位
000000000000000000000000f8905f04bde033c0a797a90ce30a8e157b3614d0    // 64 位 后面 1个零 是借amount的
00000000000000000000000000000000000000000000000013fbe85edc900000   // 64 位 后面 1个零 EVM补的

EVM 是通过 CALLDATALOAD 指令从输入数据中获取函数参数的,因此它会先从后面的 amount 参数里“借”1 个 0 来补足前面的地址参数。当它要加载 amount 参数的时候,发现位数不够,会在右边补 0。

此时 amount 由 13fbe85edc90000 改为了 13fbe85edc900000,解析出来的数据由 90000000000000000 变成了 1440000000000000000

这个值是 16 进制表示的,每移动 1 位,就会乘以 16 倍,移动两位 16x16=256 倍。这个攻击的得名也因特殊的地址截断方式,而称为“短地址攻击”。那么,如何防护这样的攻击呢?

总结

短地址攻击是利用 EVM 在参数长度不够时自动在右方补 0 的特性,通过去除钱包地址末位的 0,达到将转账金额左移放大的效果。目前主要依靠客户端主动检查地址长度来避免该问题,另外 web3 层面也增加了参数格式校验。虽然 EVM 层仍然可以复现,但是在实际应用场景中基本没有问题。

由于这数据最终进入的是 EVM 虚拟机,所以在到达虚拟机之前,我们可以做如下防护:

  • 智能合约在 transfer()函数内强制检查 len(msg.data == 68) ,不让输入数据过短。
  • 交易所或者桥的发送服务,检查接到的提币请求,地址格式长度是否合规。比如做一下 web3.utils.toChecksumAddress(address),使用校验和地址操作。
  • 前端使用合约派生出来的方法调用比如 xxContract.tracnsfer(userAddress,amount).send(),不要使用 sendRawTransaction()
    • 常规调用无法触发。通过 remix 时候客户端会检查地址长度。前端通过sendTransaction()时候,web3 中也加了保护。
    • 但是如果前端使用 sendRawTransaction() 就会触发此 BUG。




以上就是本篇文章的全部内容了,希望对你有帮助。

>> 本站不提供评论服务,技术交流请在 Twitter 上找我 @anbang_account