区块链安全

一个无源码合约的漏洞证伪

参与了一个 NFT 项目的内测,然后想着能不能找出一些漏洞。过程中,虽然最后发现了其实无法利用,但是过程中涉及到了和无源码合约交互,那我也记录下来,还是可以学到一些东西的。

我在 NFT 的特权账户的相关交易中,发现了这个交易:
https://bscscan.com/tx/0x2985b32d7cd6acc8dcc3523a758a55480801da979cfbe72e70c255bba3795b19

我发现了这个 recoverToken(address _token, uint256 amount) 函数的实际作用是给某个 recipient 地址转入 amount 数量的 _token。那么既然是 BSC 链上的,_token 一般是 BEP20 或 ERC20 代币。

如果这个函数的可见性是 public 或者 external,也就是能被外部任意账户调用的话,其实就能够通过这个函数转出这个合约的余额。而且因为这个合约闭源,也不是完全没可能。因为这个合约是开发相关的,所以下次可能还有钱转入,就有可能能通过这个函数转出其中的某种代币。

这个方法属于是 https://bscscan.com/address/0xa2a032f5d0e419d7f01816309efe001f4023c5d7#code 合约的,合约是不开源的。于是尝试逆向,逆向的话,我们很容易看到某个函数是不是被某个 modifier 限定了。

但不凑巧的是,对于这个函数签名为 0xb29a8140 的函数,刚好逆不出来其代码(https://bscscan.com/bytecode-decompiler?a=0xa2a032f5d0e419d7f01816309efe001f4023c5d7):

所以我们只能直接试试,尝试调用,于是就有了一个需求,和这个不开源的合约进行交互,调用其函数。

如何和不开源的合约交互?感觉介绍比较好的一篇文章是:https://xz.aliyun.com/t/6900

在这里,我尝试模拟出 recoverToken(address _token, uint256 amount) 函数的具体实现,其实这个函数的具体作用很简单,就是转 bep20/erc20 代币,于是我是这么写的合约:

因为我一会儿只用这个函数,所以其他的函数我就不定义了。然后我将其部署到那个 bsc 链上的闭源合约地址:

部署好之后,因为那个地址本身没钱了,我先给其转了一种 BEP20 代币(BUSD),然后尝试对其进行调用:

注意①处就是那个闭源合约的地址,②处是 BUSD 合约地址,③处是转账的金额,为了测试我们可以设为一个较小的值。

然后尝试调用发现告警:

至此,就能看出这个函数其实是有修饰符 onlyGovernance 的,也就是有权限保护。当然就没有被利用风险了。

一个漏洞要么证明要么证伪,所以整个过程我觉得还行,也有收获。后续将继续尝试通过自己构造闭源合约函数的 abi 以及 calldata 来和闭源合约进行交互。

感谢 @r4v3n 的金钱赞助,感谢 @Rivaill 一起讨论,感谢 @R3start,@Chopper_G 尝试金钱赞助。