合约地址
- 有漏洞的合约: 0x1b75b90e60070d37cfa9d87affd124bb345bf70a
- 修复后的合约: 0xFEC6F679e32D45E22736aD09dFdF6E3368704e31
- 漏洞的原因: 将要创建的合约地址,如果因为攻击者提前转入资金,会导致业务失败。
- 漏洞导致的损失: 无资金损失
场景描述
这是一个未产生损失的合约,引起的是一个生成代码。
参与者可以通过 Edgeware 发布在以太坊上的 Lockdrop 合约进行锁仓,成功后会生成一份属于自己权限控制下的独立 Lock 合约。
function lock(Term term, bytes calldata edgewareAddr, bool isValidator)
external
payable
didStart
didNotEnd
{
uint256 eth = msg.value;
address owner = msg.sender;
uint256 unlockTime = unlockTimeForTerm(term);
// Create ETH lock contract
Lock lockAddr = (new Lock).value(eth)(owner, unlockTime);
// ensure lock contract has all ETH, or fail
// ❌ 这一行可能会因为攻击而导致失败
assert(address(lockAddr).balance == msg.value);
emit Locked(owner, eth, lockAddr, term, edgewareAddr, isValidator, now);
}
Lock 合约的金额必须等于参与者锁仓时发送的金额,如果不等于,交易失败。这个失败会导致参与者的 Lock 合约瘫痪而形成拒绝服务,直接后果就是:假如攻击持续着,Edgeware 这个 Lockdrop 机制将不再可用。但这个漏洞对参与者的资金无影响。
攻击者可以通过 以太坊黄皮书 提前推测出参与者的 Lock 合约地址,只需提前往参与者的 Lock 合约地址随便转点 ETH 就好。这样用户的资金和合约内的 ETH 只要金额不想等,就会失败。
修复方式
assert(address(lockAddr).balance == msg.value);
改为:
assert(address(lockAddr).balance >= msg.value);
反思
尽量使用代理合约,可以实现合约升级。