ERC20短地址攻击
今天重看USDT合约的代码,在BasicToken里有如下代码
modifier onlyPayloadSize(uint size) {
require(!(msg.data.length < size + 4));
_;
}
function transfer(address _to, uint _value) public onlyPayloadSize(2 * 32) {
// ......
}
}
modifier onlyPayloadSize是确保payload是68,意思是前4字节函数选择器(函数签名),后面两个参数每个占32字节,一共是4+32+32=68字节,必须是满足这个长度。详见如下表:
| 部分 | 含义 | 长度(字节) |
|---|---|---|
| ① | 函数选择器(keccak256("transfer(address,uint256)") 前4字节) |
4 |
| ② | _to 参数(address,占 32字节槽,右对齐,左补零) |
32 |
| ③ | _value 参数(uint256,占 32字节) |
32 |
| 合计 | — | 68 字节 |
然后,这个是为了预防所谓的短地址攻击。
具体短地址攻击手法:
1、攻击者构造了0x1111111111111111111111111111111111111100地址,并掌握私钥。
2、攻击者故意将0x11111111111111111111111111111111111111作为第一个参数 _to,然后第二个参数 _value正常传个金额,比如00000000000000000000000000000000000000000006765c793fa10079d0000000
3、将上述三个部分组装成 calldata传给一个 有缺陷的服务,这个服务提交给EVM执行的时候,会按照如下方式进行参数提取,前4字节不变,_to参数会提取0x1111111111111111111111111111111111111100,但是结尾的“00”实际上是截取的 _value参数的最开头的“00”,然后提取 _value的时候因为前边被截取了“00”会发现少了1个字节,所以会在右侧自动补齐“00”,最后 _value变成了000000000000000000000000000000000000000006765c793fa10079d000000000,相当于16进制左移了两位,变大了256倍!
4、这样攻击者成功的提取了256倍的金额到0x1111111111111111111111111111111111111100地址!
浙公网安备 33010602011771号