区块链安全

Foundry 入门实战

前言

首先庆祝一下我给 Solidity 提的关于 CFG 的 PR 他们合并了,以后也是 Solidity 贡献者啦🎉🎉🎉 – https://github.com/ethereum/solidity/pull/13709

回到正题,Foundry 是测试部署合约的套件,但是对于安全工程师来讲,我们主要看中其测试功能。关于 Foundry 的基本资料我已不用赘述,但是最香的一点就是用 Solidity 来写攻击合约。比如 hardhat 这种合约+脚本的模式:

很显然 Foundry 的测试更精炼:

浅浅对比一下攻击脚本的文件数和文件树。

在本文中,我总结了上手 Foundry 的最小化知识点。以下进入正文。

官方文档

https://book.getfoundry.sh/

计算函数签名

(base) ➜  ~ cast 4byte 0xa9059cbb
transfer(address,uint256)

(base) ➜  ~ cast keccak “transfer(address,uint256)”
0xa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b

(base) ➜  ~ cast sig “transfer(address,uint256)”
0xa9059cbb

十六进制数转十进制

(base) ➜ ~ cast –to-dec 0x00000000000000000000000000000000000000000000bdb51a04b5aa8eb6431e
895868000762793410577182

复现

  1. 创建空文件夹,无法在非空文件夹初始化
  2. forge init –no-commit
  3. test 文件夹里写测试;🌟
    src写合约(一般用于部署);
    scrip一般写一些执行脚本,比如部署的时候,写多个调用
    注:大部分复现都不用管src,test里面都能做

写 EXP 的一些技巧

已知地址来实例化合约

不管合约是否开源,如果确定合约里面的方法,直接创建一个 interface 来定义需要的方法。如:
interface A{};
A a=A(address)
调用直接 a.方法名()
参考 – https://solidity-by-example.org/interface/

使用接口中的结构体

直接接口引用,而非实例化之后引用。方法需要实例化后引用,而结构体不是。如:

interface IUniswapV3Router {
    struct ExactInputSingleParams {
        address tokenIn;
        address tokenOut;
    }
}


使用时候:

contract AttackTest is Test {
    function swapUSDC() public{
        IUniswapV3Router.ExactInputSingleParams memory s = IUniswapV3Router.ExactInputSingleParams({
          tokenIn:UERII_address,
          tokenOut:USDC_address,
        });
        UniswapV3Router.exactInputSingle(s);
    }
}

实战:20221017 Uerii Token – Access Control

此次攻击的相关资料

是我专门找的一个比较简单的复现,最后根据官方文档和上面的一些最小化知识点就应该没问题。主要是还原根据 access control 有问题的 mint() 函数去 mint 两次,最终通过 Uniswap V3 swap 成 $USDC,然后又 swap 成 $WETH 的过程。

我自己写的 POC如下,供参考:
https://github.com/ChrisXXXXXXX/test/tree/main/20221017%20Uerii%20Token%20-%20Access%20Control