使用Slither检测MISO和Opyn的msg.value重用漏洞

本文详细介绍了如何利用Slither工具检测智能合约中的msg.value重用漏洞,包括Opyn和MISO的具体案例。通过分析循环中的msg.value和delegatecall使用,展示了Slither的新检测器实现及其在实际漏洞发现中的应用。

使用Slither检测MISO和Opyn的msg.value重用漏洞

2021年8月18日,samczsun报告了SushiSwap的MISO智能合约中的一个关键漏洞,该漏洞使约3.5亿美元(10.9万ETH)面临风险。这个问题与2020年8月对Opyn代码库进行的攻击类似。

在报告发布时,我正在Trail of Bits完成我的区块链安全实习,在那里我深入了解了Slither的功能。我立即思考是否可以为这些漏洞创建Slither检测器。答案是肯定的!今天,我们发布两个新的开源检测器,分别可以检测Opyn和MISO漏洞:msg-value-loop和delegatecall-loop。

循环中的msg.value?请避免!

MISO和Opyn漏洞的根本结果是相同的:多次重用相同的msg.value金额。区别在于,msg.value在Opyn中被显式使用(msg.value),而在MISO中被隐式使用(delegatecall)。

让我们看一个简单的例子来演示这个漏洞。

在Opyn的情况下,msg.value在一个payable函数的循环中使用。如果使用多个接收者调用addBalances(),相同的msg.value将为每个接收者重用,尽管只发送了一个接收者的相应ETH。

1
2
3
4
5
6
7
8
contract C {
  mapping (address => uint256) balances;                
  function addBalances(address[] memory receivers) public payable {
            for (uint256 i = 0; i < receivers.length; i++) {
                                balances[receivers[i]] += msg.value;
            }
  }
}

在MISO的情况下,漏洞的来源是在一个payable函数的循环中的delegatecall,该函数还调用了另一个payable函数。Delegatecall调用一个函数,同时保持当前合约的上下文、发送者和值。这是对MISO漏洞的简化解释;更多细节,我建议您阅读samczsun的博客文章。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
contract C {
  mapping (address => uint256) balances;
 
  function addBalance(address a) public payable {
                balances[a] += msg.value;
  }         
 
  function addBalances(address[] memory receivers) public payable {
                for (uint256 i = 0; i < receivers.length; i++) {
                                address(this).delegatecall(abi.encodeWithSignature(addBalance(address), receivers[i]));
                }
  }
}

Slither的新检测器

通过运行Slither来检测循环中的delegatecall和msg.value调用,我们得到以下结果:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ slither --detect delegatecall-loop Delegatecall.sol
C.addBalances(address[]) (delegatecall.sol#10-15) has delegatecall inside a loop in a payable function: address(this).delegatecall(abi.encodeWithSignature(addBalance(address),receivers[i])) (delegatecall.sol#12)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation/#payable-functions-using-delegatecall-inside-a-loop
Delegatecall.sol analyzed (1 contracts with 1 detectors), 1 result(s) found
 
$ slither --detect msg-value-loop Msgvalue.sol
C.addBalances(address[]) (msgvalue.sol#7-12) use msg.value in a loop:
balances[receivers[i]] += msg.value (msgvalue.sol#9)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation/#msgvalue-inside-a-loop
Msgvalue.sol analyzed (1 contracts with 1 detectors), 1 result(s) found

这两个检测器使用相同的逻辑实现,利用CFG表示和Slither的中间语言表示SlithIR。检测器遍历合约的payable函数节点,并检查当前节点是否进入或退出循环。现在,SlithIR来帮助我们。两个检测器的实现有所不同,它们遍历节点的SlithIR操作;msg-value-loop检查当前操作是否读取msg.value(参见检测器代码此处),而delegatecall-loop检查当前操作是否为delegatecall(参见检测器代码此处)。

让我们在发现易受攻击的智能合约上尝试这些检测器。

Opyn

1
2
3
4
$ slither 0x951D51bAeFb72319d9FBE941E1615938d89ABfe2 --detect msg-value-loop
OptionsContract._exercise(uint256,address) (crytic-export/etherscan-contracts/0x951D51bAeFb72319d9FBE941E1615938d89ABfe2-oToken.sol#1816-1899) use msg.value in a loop: require(bool,string)(msg.value == amtUnderlyingToPay,Incorrect msg.value) (crytic-export/etherscan-contracts/0x951D51bAeFb72319d9FBE941E1615938d89ABfe2-oToken.sol#1875)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation/#msgvalue-inside-a-loop
0x951D51bAeFb72319d9FBE941E1615938d89ABfe2 analyzed (13 contracts with 1 detectors), 1 result(s) found

SushiSwap的MISO

1
2
3
4
$ slither 0x4c4564a1FE775D97297F9e3Dc2e762e0Ed5Dda0e --detect delegatecall-loop
BaseBoringBatchable.batch(bytes[],bool) (contracts/Utils/BoringBatchable.sol#35-44) has delegatecall inside a loop in a payable function: (success,result) = address(this).delegatecall(calls[i]) (contracts/Utils/BoringBatchable.sol#39)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation/#payable-functions-using-delegatecall-inside-a-loop
0x4c4564a1FE775D97297F9e3Dc2e762e0Ed5Dda0e analyzed (21 contracts with 1 detectors), 1 result(s) found

结论

总之,Slither是预防智能合约安全漏洞的强大工具,并且可以通过创建新的检测器来扩展。如果您想了解更多关于这个工具的信息,请查看我们的“构建安全智能合约”指南。

我在Trail of Bits的实习很有趣,帮助我提高了安全技能,并学会了如何更好地进行审计。如果您有兴趣拥有类似的经历,可以申请加入我们作为区块链安全学徒。

如果您喜欢这篇文章,请分享: Twitter LinkedIn GitHub Mastodon Hacker News

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计