DeFiVulnLabs靶场全系列详解(三十)空循环绕过验证empty-loop

admin 2025年4月29日09:22:27DeFiVulnLabs靶场全系列详解(三十)空循环绕过验证empty-loop已关闭评论2 views字数 1698阅读5分39秒阅读模式
01
前言
此内容仅作为展示Solidity常见错误的概念证明。它严格用于教育目的,不应被解释为鼓励或认可任何形式的非法活动或实际的黑客攻击企图。所提供的信息仅供参考和学习,基于此内容采取的任何行动均由个人全权负责。使用这些信息应遵守适用的法律、法规和道德标准。
DeFiVulnLabs一共有47个漏洞实验,包括各种经典的合约漏洞和一些少见的可能造成安全问题的不安全代码,本系列将逐一解析每个漏洞,包括官方的解释和自己的理解。
02
空循环绕过
漏洞解析:
合约可以通过校验一个签名来还原其地址,我们通过这个签名来校验是否该笔交易经过验证,签名可能会存在多签,使用数组和循环是为了支持多重签名机制。
但是显然下面的合约不是多签合约验证,然后由于错误的数组限制,传入的数组未经过校验从而产生了漏洞,攻击者可以传入一个恶意的数组(空数组)从而绕过签名的校验。
代码解析:
合约代码主要有两个方法verifySignatures和withdraw方法,
verifySignatures是一个生成签名的方法,而withdraw是一个批量验证签名的提现函数。我们可以传入一个合法的签名给withdraw,然后来进行提现。
// SPDX-License-Identifier: MITpragma solidity ^0.8.0;contract SimpleBank {// 构造函数,允许在初始化时转入以太币constructor() payable {}    struct Signature {        bytes32 hash;        uint8 v;        bytes32 r;        bytes32 s;    }//校验签名function    verifySignatures(Signature calldata sig) public{            //ecrecover 是内置函数,用于从签名中恢复原来的值            require(            //比较调用者地址和签名里恢复的地址是否一致            msg.sender == ecrecover(sig.hash, sig.v, sig.r, sig.s),            "Invalid signature"        );    }//提现,传入签名数组(恢复地址)function  withdraw(Signature[] calldata sigs) public{//开始循环          for (uint i = 0; i < sigs.length; i++) {            Signature calldata signature = sigs[i];              //校验地址是否一致             verifySignatures(signature);          }            //给调用者发送1ether            payable(msg.sender).transfer(1 ether);          }          receive() external payable {}}
如果传入的签名是数组是正确的话,那么就给调用者发送1eth的奖励,但是攻击者可以传入sigs=[],由于传入的Signature[] 为[],长度为0。
因此这一段代码就会直接跳过,不再执行校验。进而直接执行 
Signature calldata signature = sigs[i];verifySignatures(signature);
然后就会发送1ether的奖励
payable(
            msg.sender).transfer(
          1 ether);
这属于一个非常典型的逻辑错误问题。
03
漏洞利用
下图所示,只需传入一个空的数组[]即可绕过签名校验,最终导致可以直接从合约里任意提取ETH
DeFiVulnLabs靶场全系列详解(三十)空循环绕过验证empty-loop

成功的从合约里进行提现最大数量的ETH

DeFiVulnLabs靶场全系列详解(三十)空循环绕过验证empty-loop

其他的合约代码出现的类似的问题

DeFiVulnLabs靶场全系列详解(三十)空循环绕过验证empty-loop
04
漏洞如何修复?

修复建议:

1、禁止传入一个空的数组,检查传入的数组是否为空。大概的意思是require(
sigs.length
> 0

2、不要使用循环对比了,直接传入一个签名对比即可

05
感谢关注
个人语雀账号:
https://www.yuque.com/iceqaq

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年4月29日09:22:27
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   DeFiVulnLabs靶场全系列详解(三十)空循环绕过验证empty-loophttps://cn-sec.com/archives/4013528.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.