CTFd é uma plataforma desenvolvida em Python para organização de jogos no estilo Capture sua Bandeira (Capture The Flag) muito comum em ambientes controlados de Segurança Ofensiva e Defensiva. Segue a url do fabricante (https://ctfd.io/)
Como demorei para encontrar tutoriais completos e atualizados resolvi juntar tudo em um só e funcional para vocês. Até a versão 18.04 do Ubuntu há um tutorial funcional utilizando a aplicação gunicorn, porém como este pacote foi descontinuado na versão 20.04 do Ubuntu tive que buscar uma forma de fazer e é este trabalho que trago para vocês de forma organizada e comando por comando.
Instalando pacotes e dependências
Antes de mais nada se faz necessário realizar a instalação de todas as dependências necessárias para o correto funcionamento do ambiente.
Adicionando repositório do nginx no ambiente
[sourcecode language="shell"]root@M4v3r1ck:~# echo deb http://nginx.org/packages/mainline/ubuntu/ `lsb_release --codename --short` nginx > /etc/apt/sources.list.d/nginx.list
root@M4v3r1ck:~# curl -s http://nginx.org/keys/nginx_signing.key | apt-key add -
[/sourcecode]
Atualizando o ambiente
[sourcecode language="shell"]root@M4v3r1ck:~# apt-get update && apt-get -y upgrade
[/sourcecode]
Instalando pacotes e dependências
[sourcecode language="shell"]root@M4v3r1ck:~# apt install nginx python3 python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools python3-venv
[/sourcecode]
Pré-configurando o NGINX
Como utilizaremos o NGINX como um proxy reverso para expor o CTFd para a internet, então vamos realizar uma pré-configuração do mesmo, para posteriormente ajustar para a configuração final. Estamos fazendo isso neste ponto pois logo a frente iremos realizar um teste inicial de acesso ao CTFd, e para isso precisaremos que essa comunicação já seja realizada via NGINX.
Edite o arquivo /etc/nginx/nginx.conf para que o mesmo fique exatamente conforme abaixo:
[sourcecode language="shell"]user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
limit_conn_zone $binary_remote_addr zone=addr:10m;
server_names_hash_bucket_size 256;
client_max_body_size 10m;
log_format log_standard '$remote_addr, $http_x_forwarded_for - $remote_user [$time_local] "$request_method $scheme://$host$request_uri $server_protocol" $status $body_bytes_sent "$http_referer" "$http_user_agent" to: $upstream_addr';
access_log /var/log/nginx/access.log log_standard;
error_log /var/log/nginx/error.log;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
[/sourcecode]
Edite o arquivo /etc/nginx/conf.d/default.conf de forma que o mesmo fique com o conteúdo abaixo:
[sourcecode language="shell"]server {
listen 80;
server_name _;
location / {
proxy_pass http://127.0.0.1:8080;
#include uwsgi_params;
#uwsgi_pass unix:/home/ctfd/CTFd/ctfd.sock;
}
}
[/sourcecode]
Reinicie o nginx
[sourcecode language="shell"]root@M4v3r1ck:~# /etc/init.d/nginx restart
[/sourcecode]
Instalando e configurando o CTFd
Agora que temos o nginx ja funcional podemos instalar o CTFd e suas dependências.
Adicione o usuário e grupo conforme abaixo
[sourcecode language="shell"]root@M4v3r1ck:~# groupadd ctfd
root@M4v3r1ck:~# adduser --disabled-password --ingroup ctfd ctfd
[/sourcecode]
Altere para o contexto do usuário
[sourcecode language="shell"]root@M4v3r1ck:~# su - ctfd
[/sourcecode]
Realize o download do CTFd. Note que o comandos está sendo executado com o usuário ctfd e dentro do seu diretório home (/home/ctfd)
[sourcecode language="shell"]ctfd@M4v3r1ck:~$ git clone https://github.com/CTFd/CTFd.git
[/sourcecode]
Agora vamos criar um ambiente virtual para isolar o nosso ambiente de outras aplicações python.
[sourcecode language="shell"]ctfd@M4v3r1ck:~$ python3 -m venv CTFd
[/sourcecode]
Isso instalará uma cópia local do Python e do pip para um diretório chamado CTFd.
Antes de instalar aplicativos no ambiente virtual, você precisa ativá-lo. Faça isso digitando:
[sourcecode language="shell"]ctfd@M4v3r1ck:~$ source CTFd/bin/activate
[/sourcecode]
Seu prompt mudará para indicar que você agora está operando no ambiente virtual. Ele se parecerá com isso (CTFd) ctfd@M4v3r1ck:~$.
Agora vamos instalar todas as dependencias python necessárias para o ctfd.
NOTA: Independente da versão do Python neste ponto usar o pip ao invés do pip3 (pois ja estamos dentro de um ambiente python3)
Primeiramente, vamos instalar o wheel com a instância local do pip para garantir que nossos pacotes serão instalados mesmo se estiverem faltando arquivos wheel:
[sourcecode language="shell"](CTFd) ctfd@M4v3r1ck:~$ pip install wheel
[/sourcecode]
Posteriormente iremos instalar o uwsgi, flask e as dependências
[sourcecode language="shell"](CTFd) ctfd@M4v3r1ck:~$ pip install uwsgi flask testresources werkzeug==0.16.0
(CTFd) ctfd@M4v3r1ck:~$ pip install -r CTFd/requirements.txt
[/sourcecode]
Agora podemos testar o sistema
[sourcecode language="shell"](CTFd) ctfd@M4v3r1ck:~$ cd CTFd
(CTFd) ctfd@M4v3r1ck:~/CTFd$ uwsgi --socket 0.0.0.0:8080 --protocol=http -w wsgi:app
[/sourcecode]
Abra o seu navegador e acesso o IP do seu servidor http://[IP], a imagem igual abaixo deve ser exibida
Quando você tiver confirmado que ele está funcionando corretamente, pressione CTRL-C na janela do seu terminal.
Acabamos agora o nosso ambiente virtual, para que possamos desativá-lo:
[sourcecode language="shell"](CTFd) ctfd@M4v3r1ck:~$ deactivate
[/sourcecode]
Agora, qualquer comando Python voltará a usar o ambiente do sistema Python.
Criar arquivo ctfd.ini
Note que neste arquivo iremos definir o modo de conexão (entre o nginx e o wsgi) como sendo um socket unix que é mais rápido e seguro.
[sourcecode language="shell"][uwsgi]
module = wsgi:app
master = true
processes = 5
pidfile = ctfd.pid
socket = ctfd.sock
chmod-socket = 660
vacuum = true
die-on-term = true
logto = /var/log/ctfd/%n.log
[/sourcecode]
Volte ao acesso como root
[sourcecode language="shell"]ctfd@M4v3r1ck:~$ exit
[/sourcecode]
Os comandos agora são executados como root.
Crie o diretório de logs e defina sua permissão
[sourcecode language="shell"]ctfd@M4v3r1ck:~# mkdir /var/log/ctfd
ctfd@M4v3r1ck:~# chown ctfd:adm /var/log/ctfd/
[/sourcecode]
Crie o arquivo para logrotate com nome /etc/logrotate.d/ctfd com o seguinte conteúdo:
[sourcecode language="shell"]/var/log/ctfd/*.log {
daily
missingok
rotate 365
compress
datetext
delaycompress
notifempty
create 640 ctfd adm
sharedscripts
postrotate
if [ -f /home/ctfd/CTFd/ctfd.pid ]; then
kill -HUP `cat /home/ctfd/CTFd/ctfd.pid`
fi
endscript
}
[/sourcecode]
Crie o arquivo /etc/systemd/system/ctfd.service
[sourcecode language="shell"][Unit]
Description=CTFd Service
After=network.target
[Service]
User = ctfd
Group = nginx
WorkingDirectory=/home/ctfd/CTFd
Environment="PATH=/home/ctfd/CTFd/bin"
ExecStart=/home/ctfd/CTFd/bin/uwsgi --ini ctfd.ini
[Install]
WantedBy=multi-user.target
[/sourcecode]
Podemos agora iniciar o serviço uWSGI que criamos e habilitá-lo para que ele seja iniciado na inicialização:
[sourcecode language="shell"]root@M4v3r1ck:~# systemctl daemon-reload
root@M4v3r1ck:~# systemctl enable ctfd
root@M4v3r1ck:~# systemctl start ctfd
[/sourcecode]
Verifique o status
[sourcecode language="shell"]root@M4v3r1ck:~# systemctl status ctfd
[/sourcecode]
Você deve ver um resultado como este:
[sourcecode language="shell"]root@M4v3r1ck:~# systemctl status ctfd
● ctfd.service - CTFd Service
Loaded: loaded (/etc/systemd/system/ctfd.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2020-06-20 03:51:28 UTC; 8s ago
Main PID: 27730 (uwsgi)
Tasks: 6 (limit: 2249)
Memory: 59.2M
CGroup: /system.slice/ctfd.service
├─27730 /home/ctfd/CTFd/bin/uwsgi --ini ctfd.ini
├─27740 /home/ctfd/CTFd/bin/uwsgi --ini ctfd.ini
├─27741 /home/ctfd/CTFd/bin/uwsgi --ini ctfd.ini
├─27742 /home/ctfd/CTFd/bin/uwsgi --ini ctfd.ini
├─27743 /home/ctfd/CTFd/bin/uwsgi --ini ctfd.ini
└─27744 /home/ctfd/CTFd/bin/uwsgi --ini ctfd.ini
Jun 20 03:51:29 ctfd uwsgi[27730]: * Loaded module, <module 'CTFd.plugins.dynamic_challenges' from './CTFd/plugins/dynamic_challenges/__init__.py'>
Jun 20 03:51:29 ctfd uwsgi[27730]: * Loaded module, <module 'CTFd.plugins.flags' from './CTFd/plugins/flags/__init__.py'>
Jun 20 03:51:29 ctfd uwsgi[27730]: WSGI app 0 (mountpoint='') ready in 1 seconds on interpreter 0x56237be7f2c0 pid: 27730 (default app)
Jun 20 03:51:29 ctfd uwsgi[27730]: *** uWSGI is running in multiple interpreter mode ***
Jun 20 03:51:29 ctfd uwsgi[27730]: spawned uWSGI master process (pid: 27730)
Jun 20 03:51:29 ctfd uwsgi[27730]: spawned uWSGI worker 1 (pid: 27740, cores: 1)
Jun 20 03:51:29 ctfd uwsgi[27730]: spawned uWSGI worker 2 (pid: 27741, cores: 1)
[/sourcecode]
Estando tudo correto agora vamos editar o nginx para se conectar ao wsgi através do socket unix que criamos.
Altere o arquivo /etc/nginx/conf.d/default.conf para:
[sourcecode language="shell"]server {
listen 80;
server_name _;
location / {
uwsgi_param Host $host;
uwsgi_param X-Real-IP $remote_addr;
uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
uwsgi_param X-Forwarded-Proto $http_x_forwarded_proto;
proxy_read_timeout 600;
proxy_connect_timeout 1d;
proxy_max_temp_file_size 5024m;
proxy_send_timeout 600;
uwsgi_read_timeout 600;
uwsgi_send_timeout 600;
include uwsgi_params;
uwsgi_pass unix:/home/ctfd/CTFd/ctfd.sock;
}
}
[/sourcecode]
Recarregue a configuração do nginx
[sourcecode language="shell"]root@M4v3r1ck:~# nginx -s reload
[/sourcecode]
Realize o teste de acesso ao CTFd através da URL http://[IP]
Agora você tem o CTFd rodando na porta 80 do seu servidor, basta o teste de acesso ao CTFd através da URL http://[IP].
Fontes: