在整理CTF中的区块链(目前多为以太坊智能合约)题目时发现这些题目有各种版本的题目部署判题逻辑,这是由于出题人在出题时是根据自己合约的不同逻辑对前人题目环境修修补补,这导致整理出的repository里堆放着各种逻辑相似却不完全相同的代码,使得调试这些题目环境的工作量变得巨大。

所谓“工欲善其事,必先利其器”,我将以太坊智能合约的题目逻辑抽象封装成了一个通用Docker镜像,一是为了将之前题目整理成可以运行的版本,二是方便之后的出题。

该项目开源在 https://github.com/chainflag/eth-challenge-base (求star),出题时只需要设置题目的相关配置文件就可以搭建出可以运行的合约题目而不再需要重复编写账户生成、合约部署、判题等逻辑代码。

快速预览

使用如下命令可以使用内置示例题目快速预览该工具的效果:

1
2
docker run -it -p 20000:20000 -e WEB3_PROVIDER_URI=https://ropsten.infura.io/v3/YOUR-PROJECT-ID chainflag/eth-challenge-base
nc 127.0.0.1 20000

asciicast

使用方式

创建自己的题目文件并将其映射到Docker容器内来运行题目:

首先我们参考example目录创建题目的相关文件,具体如下:

  • contracts 目录用于存放题目的合约, 我们要为题目合约编写isSolved() 函数以判断选手是否成功解题。对于有多个合约的题目,可以在一个合约的构造函数中完成其他合约的部署逻辑。

  • challenge.yml 用于指定题目描述、Flag、要部署的合约名、构造函数的参数和金额、是否显示合约源代码。此外还可以为solved_event选项设置Event名配置成当选手触发该Event时发放Flag。

  • .env 用来设置Docker容器的环境变量,包括web3连接地址、 用于管理会话的token密钥(默认使用openssl rand随机生成)以及工作量证明的难度(默认无POW)。

这样我们的题目就准备好了,之后使用eth-challenge-base镜像启动容器时将contracts目录和challenge.yml文件映射到Docker容器内,并使用.env文件配置容器的环境变量就可以启动我们编写的题目了。具体命令如下:

1
docker run -d -p 20000:20000 --env-file .env -v `pwd`/contracts:/home/ctf/contracts -v `pwd`/challenge.yml:/home/ctf/challenge.yml chainflag/eth-challenge-base:0.9.3

当前Docker镜像版本tag为0.9.3,可以在项目仓库的releases界面获取最新版本号。

或者使用写好的docker compose文件来完成这一步。

1
docker-compose up -d

由于容器启动后需要下载solc并编译合约,因此要等待1-2分钟后才可以使用nc连接上该题目。

致谢

该项目的逻辑参考了pikachu编写 https://github.com/hitcxy/blockchain_template ,以太坊智能合约的编译使用了eth-brownie这个Python版的合约开发框架,xinetd的配置来自于paradigm-ctf-2021,POW生成和验证的逻辑参考了 https://github.com/balsn/proof-of-work ,在此表示感谢。同时该项目的完善也离不开qczbhds的试用反馈和协助开发,以及未来的contributor