paradigm 2022 ctf ——Hint-finance

题目分析

paradigm 2022 ctf ——Hint-finance

题目提供了三个合约,要求我们调用isSolved函数成功返回true。

paradigm 2022 ctf ——Hint-finance

要求我们拿走金库中百分之九十九的初始代币,也就是题目提供的三个代币地址,根据Etherscan可查询到三个代币分别为PNT,AMP和SAND。而PNT和AMP都是ERC777代币,SAND是ERC20代币。

分别进行分析三个合约。

paradigm 2022 ctf ——Hint-finance

该合约只提供创建金库已经提供奖励代币的功能。

paradigm 2022 ctf ——Hint-finance

HintFinanceVault合约主要功能存,取以及闪电贷。

paradigm 2022 ctf ——Hint-finance

Setup合约,顾名思义,部署合约。根据合约初始的三个代币地址,分别创建了三个抵押金库,我们要达到的目的就是拿走金库中百分之九十九的代币。

paradigm 2022 ctf ——Hint-finance

题目除了这三个合约之外,在setup中提供了六个地址,三个为我们需要的token,三个为奖励token,都能在EtherScan中查询到对应的合约。

漏洞分析

ERC777 token分析

PNT和AMP都为ERC777代币,联想到2021年八月份Cream Finance遭遇的闪电贷攻击,也就是ERC777代币存在的重入攻击,我们重点关注重入来审一下代码。

paradigm 2022 ctf ——Hint-finance

ERC777的token在转账之前,都需要到EIP1820的地址上进行注册,也就是调用setInterfaceImplementer方法,传入注册的key和address。

paradigm 2022 ctf ——Hint-finance

paradigm 2022 ctf ——Hint-finance

ERC777 token会在tansfer和transferFrom的时候都进行判断,其中_callTokensTosend就是发送方的回退函数,_callTokenReceived就是接收方的回退函数。而由于ERC777存在回退函数的机制,Vault合约中的depositwithdraw函数都没有nonReentrant的限制。

继续观察withdraw函数,发现他并没有在转账之前修改状态变量,而是在转账后才修改,如果我们利用这一点进行重入,那么在重入的过程当中,totalSupply变量并不变,而我们在token中的余额在转账过程中已经发生了变化。

而在deposit函数中,恰巧就是通过totalSupply和我们token的余额来计算出share变量的。如果totalSupply没变,但我们的余额却减小了,那么计算出来的share就会比正常情况下大很多倍。

如果我们通过withdraw函数来重入到deposit函数中,我们就可以在deposit函数中得到一笔大的share,再回到withdraw函数中扣除一笔小的share,这样我们通过重入就能够无限的套利,从而取出vault中的绝大部分share,满足题意。

重入函数如下图所示,那么PNT和AMP即都可以通过这种方式进行重入从而完成攻击

paradigm 2022 ctf ——Hint-finance

erc20 token分析

Sand token是一个普通的erc20代币,所以无法进行重入,所以需要对sand合约进行逻辑审计。

paradigm 2022 ctf ——Hint-finance

首先我们注意到Vault合约中还存在另一个功能函数flashloan,且其中包含一个回退函数onHintFinanceFlashloan.而ERC20作为最基础的代币标准,攻击方式非常有限,其中一种很常用的就是想办法让token的owner对我们进行approve。

通过对Sand合约进行审计,我们注意到Sand中并不只是一个基础的ERC20,还存在这样一个父合约。

paradigm 2022 ctf ——Hint-finance

其中的approveAndCall函数也会让调用者向对应地址进行approve,还会根据传入的data去target地址中调用相应的函数。如果我们能让Vault合约调用这个函数或者approve函数,即可拿到权限。看起来好像并没有能让Vault调用这两个函数的方法,flashloan中唯一存在的一个外部函数调用就是他自己的回退函数_onHintFinanceFlashloan

但经过对比,发现approveAndCallonHintFinanceFlashloan的函数选择器是相同的,也就是说,在flashloan函数中由于函数选择器相同的原因,可以调用到approveAndCall函数,从而达到目的。

参数构造

首先IHintFinanceFlashloanReceiver(msg.sender).onHintFinanceFlashloan(token, factory, amount, isUnderlyingOrReward, data);调用的msg.sender的函数,所以调用者必须是Sand合约,我们需要先调用approveAndCall函数通过传入的data调用flashloan函数。

paradigm 2022 ctf ——Hint-finance

paradigm 2022 ctf ——Hint-finance

由于approveAndCall和onHintFinanceFlashloan的参数个数并不相同

paradigm 2022 ctf ——Hint-finance

从上图能看出来,target =token,amount = uint256(factory),而本来应该在第三个slot中的innerdata,也就是右边amount的值,为了符合approveAndCall函数中第三个参数是一个bytes memory,所以amount的值只能是innerdata所在的位置,也就是0xa0,这将让approveAndCall在尝试获取数据的时候会找到data提供的数据。而isUnderlyingOrReward部分由于是bool类型,所以用0填充即可。

又因为approveAndCall函数中限制了data的第一个参数必须是msg,sender,所以data第一个参数必须是vault的地址。

且由于在flashloan中调用对象是代币合约类型,所以攻击合约也需要伪装成代币合约。


原文始发于微信公众号(ChainSecLabs):paradigm 2022 ctf ——Hint-finance

版权声明:admin 发表于 2024年4月27日 下午1:01。
转载请注明:paradigm 2022 ctf ——Hint-finance | CTF导航

相关文章