CTFd-Whale高级部署

  • 2021年5月26日
  • CTF, Security, ...
  • visibility 277 views

事情的起因是,我想把ctfd的网站服务器和靶机服务器分离开。

现在我租了两台服务器,一台在hk,做ctfd服务器,不需要备案就能提供网页服务,但价格稍贵,带宽开了3M,做网页足够,券后100出头(200-100);另一台在成都,TX云的SA2系列性价比很高,配合新人优惠券就是半价(窃喜),能开比较不错的配置,4核8G+7M带宽500多一点点,优惠券500-250。

那么要安全地调用靶机的api来开启docker题目,并提供动态flag,就需要配置docker的tls认证和frpc的basic auth

整个架构看起来是这样的

1. 配置安全的docker api

参考了这篇文章,在此做备份。

配置证书的目的是为了验证CTFd服务器的身份,避免靶机服务器被扫到端口就能被随意利用。

1.1 服务器配置(靶机服务器)

1.1.1 创建certs文件夹,用来存放CA私钥和公钥

以下操作均为root用户

mkdir -pv /etc/docker/certs
cd /etc/docker/certs

1.1.2 创建密码

需要连续输入两次相同的密码

openssl genrsa -aes256 -out ca-key.pem 4096

1.1.3 依次输入密码、国家、省、市、组织名称等(除了密码外其他的可以直接回车跳过)

openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem

1.1.4 生成server-key.pem

openssl genrsa -out server-key.pem 4096

1.1.5 生成server.csr(把下面的IP换成你自己服务器外网的IP或者域名)

openssl req -subj "/CN=123.123.123.123" -sha256 -new -key server-key.pem -out server.csr

1.1.6 配置白名单

0.0.0.0表示所有ip都可以连接。(这里需要注意,虽然0.0.0.0可以匹配任意,但是仍需要配置你的外网ip和127.0.0.1,否则客户端会连接不上)

echo subjectAltName = IP:0.0.0.0,IP:123.123.123.123,IP:127.0.0.1 >> extfile.cnf

或者也可以设置成域名

echo subjectAltName = DNS:www.example.com,IP:123.123.123.123,IP:127.0.0.1 >> extfile.cnf

1.1.7 将Docker守护程序密钥的扩展使用属性设置为仅用于服务器身份验证

echo extendedKeyUsage = serverAuth >> extfile.cnf

1.1.8 输入之前设置的密码,生成签名证书

openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf

1.1.9 生成供客户端发起远程访问时使用的key.pem

openssl genrsa -out key.pem 4096

1.1.10 生成client.csr(和上面server.csr的IP相同)

openssl req -subj "/CN=123.123.123.123" -new -key key.pem -out client.csr

1.1.11 创建扩展配置文件,把密钥设置为客户端身份验证用

echo extendedKeyUsage = clientAuth > extfile-client.cnf

1.1.12 生成cert.pem,输入前面设置的密码,生成签名证书

openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile-client.cnf

1.1.13 删除不需要的配置文件和两个证书的签名请求

rm -v client.csr server.csr extfile.cnf extfile-client.cnf

1.1.14 为了防止私钥文件被更改以及被其他用户查看,修改其权限为所有者只读

chmod -v 0400 ca-key.pem key.pem server-key.pem

1.1.15 为了防止公钥文件被更改,修改其权限为只读

chmod -v 0444 ca.pem server-cert.pem cert.pem

1.1.16 修改Docker配置,使Docker守护程序仅接受来自提供CA信任的证书的客户端的连接

拷贝安装包单元文件到/etc,这样就不会因为docker升级而被覆盖

cp /lib/systemd/system/docker.service /etc/systemd/system/docker.service

打开/etc/systemd/system/docker.service, 找到ExecStart=/usr/bin/dockerd

ExecStart=/usr/bin/dockerd ...这一行删掉,改成下面的段落

ExecStart=/usr/bin/dockerd --tlsverify \
--tlscacert=/etc/docker/certs/ca.pem \
--tlscert=/etc/docker/certs/server-cert.pem \
--tlskey=/etc/docker/certs/server-key.pem \
-H tcp://0.0.0.0:2376 \
-H unix:///var/run/docker.sock

1.1.17 重新加载daemon并重启docker

systemctl daemon-reload
systemctl restart docker

1.1.18 打包证书

tar cf *.pem certs.tar

然后通过比如stfp复制到客户端去

1.2 客户端配置(CTFd所在服务器)

仍然是root用户

1.2.1 创建证书目录

cd CTFd
mkdir docker-certs
cd docker-certs

1.2.2 将ca.pem cert.pem key.pem这3个文件拷贝到当前目录

tar xf certs.tar CTFd/docker-certs

1.2.3 使用docker客户端测试(注意修改证书路径)

docker --tlsverify \
    --tlscacert=/CTFd/docker-certs/ca.pem \
    --tlscert=/CTFd/docker-certs/cert.pem \
    --tlskey=/CTFd/docker-certs/key.pem \
    -H=<server_ip>:2376 version

1.2.4 修改whale的docker配置页面

本来whale还没支持tls,联系上维护者提了个需求,他半小时就写好push了

frp配置在下一段

务必非常小心保管这些key,它们就跟服务器root密码一样重要(众所周知docker是可以进行真实主机提权的)

2. 配置安全的frp服务

在这次部署的情况中,两台独立的vps都有各自的公网ip,故frps和frpc都在靶机服务器,ctfd服务器不需要frp

如果靶机在内网的话,frps可以放到公网服务器,frpc改一下server_ip就好

2.1 修改CTFd服务器的docker-compose.yml

因为之前照着赵师傅的博客配置加了frp的配置,现在需要删掉frp有关的所有服务和网络,回退到CTFd官方repo的配置

2.2 配置靶机服务器

首先拉取frankli0324/ctfd-whale/ctfd-target/docker-compose.yml(稍后pr)

frps段里面映射的端口范围可以按需更改

由于我觉得并不需要http子域名,此时是ip+端口直接访问

然后修改frp目录下的frps.ini

建议把token换成一个随机字符串,比如去生成一个UUID

[common]
bind_port = 6490
token = random_token

以及frpc.ini

[common]
token = random_token
server_addr = 172.1.0.20
server_port = 6490
pool_count = 200
admin_addr = 0.0.0.0
admin_port = 7400
admin_user = admin_user
admin_pwd = admin_password

其中admin_port被映射到了9003端口,在ctfd的配置里需要写成这样

然后是frpc的模板,在ctfd里写成和上面提到的一样。注意之后不要手动更改靶机服务器里的frpc.ini,此文件会由ctfd-whale远程修改。

3. 单容器题目测试

此时应该就装好了,跑个测试题目看看

类型选动态容器

看看效果如何

OK,能用

另外提一下,题目的动态flag由whale生成,不需要手动在challenge的页面里添加flag值,whale会在容器生成时把生成的flag值添加到$FLAG环境变量,故只要选手通过任何方式拿到$FLAG的值就可以了,这样能有效避免交换flag作弊。




没有评论


你先离开吧:)



发表评论

邮箱地址不会被公开。 必填项已用*标注