一个字节缺失,转账金额放大256倍:短地址攻击的数学魔术

admin 2026-03-03 06:33:31 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文解析以太坊短地址攻击原理,阐述EVM自动补全机制致转账金额放大漏洞。文章拆解攻击链构造与Golem事件案例,提供静态检测、机器学习检测及动态测试方案。建议通过合约层验证地址长度、使用SafeERC20库及交易所后端校验进行防御,警惕历史漏洞变种。 综合评分: 91 文章分类: 漏洞分析,区块链安全,代码审计


cover_image

一个字节缺失,转账金额放大256倍:短地址攻击的数学魔术

原创

梦到什么写什么 梦到什么写什么

逍遥子讲安全

2026年2月24日 21:26 广东

一个字节的缺失,让转账金额凭空放大256倍——这不是魔术,是EVM自动补全机制下的精确数学。

2017年,Golem项目首次披露了一个影响Poloniex等主流交易所的漏洞:攻击者通过构造畸形的地址参数,成功从交易所窃取了大量ERC20代币。问题的根源不在合约逻辑,而在EVM对输入数据的自动补全机制

本文将完整拆解短地址攻击的底层原理、攻击链构造、实战案例以及自动化审计思路。全是干到拧不出水的干货。

第一章 短地址攻击的底层原理:EVM的“善意”如何被利用

1.1 核心漏洞点:自动补全机制

以太坊虚拟机(EVM)在处理交易数据时,遵循严格的ABI编码规范。当外部调用智能合约函数时,交易数据按以下格式编码:

函数选择器(4字节) + 参数1(32字节) + 参数2(32字节) + ...

对于ERC20的transfer(address to, uint256 amount)函数,正常调用的编码数据为:

  • 4字节:0xa9059cbbtransfer的函数选择器)
  • 32字节:接收地址(实际只使用后20字节,前12字节填充0)
  • 32字节:转账金额

关键点:当某个参数(如地址)的实际数据长度不足32字节时,EVM会自动在低位(右侧)进行补0,凑足32字节。

1.2 攻击的核心:地址缺失引发的“数据偏移”

短地址攻击的巧妙之处在于:攻击者故意提供一个少于20字节的地址参数,触发EVM的自动补全机制,导致原本属于金额的字节被“拉”到地址段补齐,而金额段缺失的字节则被补0——最终结果是金额被乘以16^(缺失字节数×2)

正常调用数据包结构

[函数选择器] [12字节填充0 + 20字节地址] [32字节金额]

攻击调用数据包结构(假设地址缺失2字节):

[函数选择器] [12字节填充0 + 18字节地址 + 2字节缺失] [30字节金额 + 2字节缺失]

EVM处理时:

  1. 检测到地址参数不足32字节,从紧随其后的金额参数中“借用”2字节补到地址段尾部
  2. 金额参数现在只有30字节,EVM自动在金额参数的尾部补2个0
  3. 最终结果:金额被扩大了256倍(2字节=16^2=256)

数学表达

  • 正常转账:transfer(0xAddress, 100)
  • 攻击转账:transfer(0xAddre, 100)(假设地址缺失1字节)
  • 实际执行:transfer(0xAddress0, 100 * 16)(金额被乘16)

第二章 攻击链的完整构造

2.1 寻找符合条件的地址

攻击需要找到一个以若干个0结尾的地址。地址越界攻击的核心是:提供的地址末尾缺失的字节数正好是0,这样从金额段“借用”的字节会被解释为金额的一部分。

构造方法: 攻击者可以通过暴力生成以太坊地址,寻找以00、0000等结尾的地址。这类地址可以提前生成,并在攻击前准备好。

2.2 攻击合约示例

漏洞合约(存在短地址风险):

soliditypragma solidity ^0.4.11;contract TestToken {    mapping (address => uint) balances;
    function TestToken() {        balances[tx.origin] = 10000;    }
&nbsp; &nbsp;&nbsp;function&nbsp;sendCoin(address to, uint amount)&nbsp;returns(bool sufficient) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if(balances[msg.sender] < amount)&nbsp;return&nbsp;false;&nbsp; &nbsp; &nbsp; &nbsp; balances[msg.sender] -= amount;&nbsp; &nbsp; &nbsp; &nbsp; balances[to] += amount;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;true;&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;function&nbsp;getBalance(address addr) constant&nbsp;returns(uint) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;balances[addr];&nbsp; &nbsp; }}

2.3 攻击数据构造

假设攻击者找到了以两个0结尾的地址:0x254d383ab537ebeab73f816df8e1598f1321bc00

攻击者调用sendCoin时,传入的地址参数截掉最后两个字节,即:

textto&nbsp;=&nbsp;0x254d383ab537ebeab73f816df8e1598f1321bcamount&nbsp;=&nbsp;1

构造的交易数据

函数选择器:0xb90b98a1(sendCoin的哈希前4字节)地址参数:0x000000000000000000000000254d383ab537ebeab73f816df8e1598f1321bc(仅19字节?此处示例数据需精确)金额参数:0x0000000000000000000000000000000000000000000000000000000000000001

实际发送的数据包(长度134字节,比正常少2字节):

0xb90b98a1&nbsp;+&nbsp;000...0254d383ab537ebeab73f816df8e1598f1321bc +&nbsp;000...0001

EVM解析时:

  1. 地址参数应为32字节,但实际只有30字节(地址部分实际19字节?需要精确计算)
  2. 从金额参数“借用”2字节补到地址段
  3. 金额参数剩余30字节,尾部自动补2个0
  4. 最终执行的转账金额:1 × 16^2 = 256个代币

攻击效果:攻击者只支付了1个代币,却成功转账256个代币。

第三章 真实案例分析:Golem事件与交易所劫持

3.1 Golem项目披露的漏洞

2017年4月,Golem项目发布了一篇博文,详细描述了一个影响Poloniex等交易所的安全漏洞。问题在于:当某些交易所处理ERC20代币交易时,没有对账户地址长度进行输入验证

攻击场景

  1. 攻击者在交易所创建提币请求,目标地址是一个精心构造的短地址(如0x1234...00,末尾含0)
  2. 交易所前端正常显示提币金额(如100个GNT)
  3. 后端构造交易数据时,直接拼接用户输入的地址字符串
  4. 由于地址末尾的0被截断,触发EVM自动补全
  5. 实际链上转账金额变为100 × 256 = 25600个GNT

后果:攻击者可以盗取交易所热钱包中的大量用户代币。

3.2 为什么交易所成为重灾区

交易所成为短地址攻击主要目标的原因:

  1. 批量处理:交易所往往批量处理提币请求,不易对每个地址进行严格校验
  2. 前端截断:前端显示地址时可能自动省略末尾的0,用户不易察觉异常
  3. 后端拼接:后端直接拼接用户输入的字符串,未进行规范化处理

3.3 漏洞修复后的残存风险

即使在EVM层面修复后,短地址攻击仍然存在变种:

  1. 多层嵌套调用:通过多层合约调用,可能在某一层触发补全
  2. 跨链桥:不同链对地址长度的处理不一致,可能在跨链时触发类似问题

第四章 深度利用:从短地址到价值倍增

4.1 金额放大倍数计算表

| 地址缺失字节数 | 缺失16进制位数 | 金额放大倍数 | 攻击效果 | | — | — | — | — | | 1字节 | 2位 | 16² = 256倍 | 1 → 256 | | 2字节 | 4位 | 16⁴ = 65536倍 | 1 → 65536 | | 3字节 | 6位 | 16⁶ = 16777216倍 | 1 → 1.67千万 | | 4字节 | 8位 | 16⁸ ≈ 4.29亿倍 | 1 → 4.29亿 |

实际限制

  • 地址以0结尾的概率:每256个地址出现1个(1字节0)
  • 地址以00结尾的概率:每65536个地址出现1个(2字节0)
  • 地址以000结尾的概率:每1677万个地址出现1个(3字节0)

攻击者需要提前生成大量地址,筛选符合条件的短地址备用。

4.2 组合攻击:短地址 + 整数溢出

在某些旧版合约中,如果同时存在整数溢出漏洞,攻击效果可能进一步放大:

solidity

// 漏洞组合示例function&nbsp;batchTransfer(address[] _receivers, uint256 _value) {&nbsp; &nbsp; uint cnt = _receivers.length;&nbsp; &nbsp; uint256 amount = cnt * _value; &nbsp;// 可能溢出&nbsp; &nbsp;&nbsp;require(balances[msg.sender] >= amount);&nbsp; &nbsp;&nbsp;// ...}

攻击者可以通过短地址攻击放大_value,再结合整数溢出,可能实现无限铸币。

第五章 自动化审计与检测

5.1 静态代码检测规则

在合约审计中,可以通过以下规则发现潜在的短地址风险:

py# 审计规则示例def&nbsp;check_short_address_vulnerability(contract_code):&nbsp; &nbsp; red_flags = []
&nbsp; &nbsp;&nbsp;# 规则1:是否直接使用外部传入的地址参数&nbsp; &nbsp;&nbsp;if&nbsp;re.search(r"function\s+\w+\s*\([^)]*address[^)]*\)", contract_code):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 检查是否有长度验证&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;not&nbsp;re.search(r"\.length\s*[=!]=\s*20", contract_code):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; red_flags.append("地址参数未进行长度验证")
&nbsp; &nbsp;&nbsp;# 规则2:是否使用assembly操作地址&nbsp; &nbsp;&nbsp;if&nbsp;"assembly"&nbsp;in&nbsp;contract_code&nbsp;and&nbsp;"address"&nbsp;in&nbsp;contract_code:&nbsp; &nbsp; &nbsp; &nbsp; red_flags.append("在汇编中操作地址,存在短地址风险")
&nbsp; &nbsp;&nbsp;return&nbsp;red_flags

5.2 基于机器学习的检测

近期研究显示,通过提取操作码和trigram特征,机器学习模型可以高效检测短地址漏洞。

| 算法 | 准确率 | 精确率 | 召回率 | F1分数 | | — | — | — | — | — | | 梯度提升 | 97.84% | 98.21% | 98.05% | 98.13% | | 随机森林 | 96.72% | 97.13% | 96.88% | 97.00% | | SVM | 94.35% | 94.87% | 94.21% | 94.54% |

特征提取方法

  • 操作码序列:提取合约字节码中的操作码序列
  • Trigram特征:将操作码序列分割为3-gram,统计频率
  • 控制流图特征:提取CFG中的异常路径

5.3 动态测试工具

py# 短地址攻击测试脚本(概念验证)import&nbsp;web3from&nbsp;web3&nbsp;import&nbsp;Web3
def&nbsp;test_short_address_attack(contract_address, target_address, amount):&nbsp; &nbsp; w3 = Web3(Web3.HTTPProvider('https://mainnet.infura.io/v3/YOUR_KEY'))
&nbsp; &nbsp;&nbsp;# 构造短地址(假设target_address以00结尾)&nbsp; &nbsp; short_address = target_address[:-2] &nbsp;# 去掉最后两个字符
&nbsp; &nbsp;&nbsp;# 构造交易数据&nbsp; &nbsp; transfer_signature = w3.keccak(text="transfer(address,uint256)")[:4].hex()&nbsp; &nbsp; address_param = short_address[2:].rjust(64,&nbsp;'0') &nbsp;# 补足64位(32字节)&nbsp; &nbsp; amount_param =&nbsp;hex(amount)[2:].rjust(64,&nbsp;'0')
&nbsp; &nbsp; data =&nbsp;'0x'&nbsp;+ transfer_signature + address_param + amount_param
&nbsp; &nbsp;&nbsp;# 发送测试交易(需在测试网进行)&nbsp; &nbsp; tx = {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'to': contract_address,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'data': data,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'gas':&nbsp;100000,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'gasPrice': w3.eth.gas_price&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;return&nbsp;tx

第六章 防御方案与最佳实践

6.1 合约层的防御

方案1:显式验证地址长度

solidityfunction&nbsp;transfer(address to, uint256 amount)&nbsp;public&nbsp;returns&nbsp;(bool)&nbsp;{&nbsp; &nbsp;&nbsp;// 验证地址长度为20字节&nbsp; &nbsp;&nbsp;require(to !=&nbsp;address(0),&nbsp;"Invalid address");&nbsp; &nbsp;&nbsp;require(to ==&nbsp;address(uint160(to)),&nbsp;"Address length mismatch");&nbsp; &nbsp;&nbsp;// 或者直接信任Solidity的类型系统,但避免使用assembly&nbsp; &nbsp;&nbsp;_transfer(msg.sender, to, amount);&nbsp; &nbsp;&nbsp;return&nbsp;true;}

方案2:使用SafeERC20库

OpenZeppelin的SafeERC20库通过封装ERC20操作,增加了安全检查:

solidityimport&nbsp;"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";contract&nbsp;Vault&nbsp;{&nbsp; &nbsp;&nbsp;using&nbsp;SafeERC20&nbsp;for&nbsp;IERC20;
&nbsp; &nbsp;&nbsp;function&nbsp;safeTransfer(IERC20 token, address to, uint256 amount) internal {&nbsp; &nbsp; &nbsp; &nbsp; token.safeTransfer(to, amount); &nbsp;// SafeERC20会自动处理地址验证&nbsp; &nbsp; }}

6.2 钱包/交易所层的防御

| 防御层级 | 具体措施 | 实施建议 | | — | — | — | | 前端 | 地址规范化显示 | 确保地址以完整40字符显示,不省略末尾0 | | 后端 | 地址参数校验 | 严格验证地址字符串长度为42(含0x) | | 交易构造 | 使用ABI编码库 | 使用web3.js/ethers.js的标准ABI编码,不手动拼接 | | 监控 | 异常交易检测 | 监控金额异常的转账交易,特别是小额测试后的大额攻击 |

6.3 EVM层的演进

随着Solidity版本升级和EVM优化,短地址攻击在最新版本中已被有效缓解

  • Solidity 0.8.x:增强了ABI编码的严格性
  • 编译器层面:自动插入长度检查
  • 历史合约和跨链交互仍存在风险,审计时必须关注

第七章 结语:一个字节的教训

短地址攻击的精髓在于:它利用了系统的“善意”——EVM的自动补全机制——将其转化为攻击武器。一个字节的缺失,通过精心构造的攻击链,最终导致金额的指数级放大。

这类漏洞给我们的启示:

  1. 永远不要信任输入数据的长度:即使EVM有自动补全机制,也必须在合约层显式验证
  2. 警惕“善意”的系统行为:自动补全、默认值、隐式转换都可能成为攻击向量
  3. 历史漏洞的变种:短地址攻击虽然“古老”,但在跨链、Layer2等新场景中可能以新面目出现

在合约审计中,短地址漏洞必须作为高危项优先排查。一个转账函数,可能就是攻击者撬动整个资金池的支点。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:逍遥子讲安全 梦到什么写什么 梦到什么写什么《一个字节缺失,转账金额放大256倍:短地址攻击的数学魔术》

评论:0   参与:  0