📑 En este blog veremos:
- 📰 ¿Qué es Docker?
- 📌 ¿Como instalar Docker?
- 📌 Como usar Docker
- 📍Desplegar nuestro primer contenedor
- 📗 Recomendaciones al iniciar nuestro contenedor
- ⚙️ Configuración de servicios
- 📌 Iniciar servicio OpenSSH
- 📌 Iniciar servicio FTP
- 📌 Iniciar servicio Apache2
- 📌 Iniciar servicio Nginx
- 📌 Crear servicio personalizado
- ⚙️ Configuración de usuarios
- 📌 Crear usuarios nuevos
- 📌 Eliminar usuarios
- ⚙️ Configuración de permisos
- 📌 Establecer permisos sudoers a usuarios
- 📌 Permisos en Apache2
- ⚙️ Configuración de Dockerfile
- 📌 Exportar contenedor a .tar
- 📝 Creación del Writeup
- 👋 Despedida
📰¿Qué es Docker?
Docker es un proyecto OpenSource. Con Docker podemos utiliizar los contenedores como máquinas virtuales muy livianas y modulares.
📌¿Como instalar Docker?
Para instalar Docker en nuestros equipos Linux solo tendremos que poner lo siguiente:
Debian/Derivados:
❯ sudo apt install docker.io
ArchLinux/Derivados:
❯ sudo pacman -S docker
Fedora/Derivados:
❯ sudo dnf install docker
📌Como usar Docker
Si queremos ver las imágenes de Docker que tengamos podremos hacer un:
❯ docker images
❯ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 35a88802559d 7 weeks ago 78.1MB
Si queremos sacar una imagen ya hecha de Ubuntu,Debian,etc… con docker pull
podremos:
docker pull debian:latest
Y nos descargará la última versión de la imagen de Debian que exista en Docker. Podemos sacar más imágenes en DockerHub
Si queremos listar los contenedores que tengamos podremos emplear docker ps
:
❯ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fc58d5436a68 ubuntu "/bin/bash" 3 hours ago Up 3 hours focused_mayer
Con docker ps
de manera predeterminada solo nos muestra los contenedores que estén activos, si queremos ver todos los contenedores tendremos que agregar el parámetro -a
o --all
:
❯ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fc58d5436a68 ubuntu "/bin/bash" 3 hours ago Up 3 hours focused_mayer
27fc4260aae8 debian "/bin/bash" 2 hours ago Exited (137) 3 seconds ago agitated_jennings
Si queremos borrar contenedores usaremos docker rm
:
Para emplear bien este comando seguiremos esta estructura:
docker rm IDCONTENEDOR
Recordemos que podemos usar el docker ps -a
para ver los ID de todos los contenedores dando si están activos o no podemos emplear docker ps
con el parámetro -a
o --all
:
❯ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7050ab52f603 debian "bash" 2 minutes ago Exited (137) About a minute ago agitated_jennings
fc58d5436a68 ubuntu "/bin/bash" 3 hours ago Up 3 hours focused_mayer
Si queremos borrar todos los contenedores a la vez podemos usar los parámetros -a
y -q
, el -q
nos servirá para pillar solo el CONTAINER ID:
❯ docker ps -aq
fc58d5436a68
27fc4260aae8
157570dd64f0
Sabiendo esto podemos dentro del docker rm
la ejecución del comando docker ps -aq
:
❯ docker rm $(docker ps -aq) --force
fc58d5436a68
27fc4260aae8
157570dd64f0
Usamos el --force
para forzar que se elimine tanto contenedores inactivos o activos.
{{< details “Estado docker ps después de eliminarlo” >}}
❯ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
{{< /details >}}
Esto mismo podemos aplicarlo a las imágenes, solo con la diferencia que no usaremos rm
emplearemos rmi
que nos servirá para eliminar imágenes Docker. Al igual que con docker ps -aq
podemos usarlo con images
:
❯ docker images -aq
2e5b8d3ef33e
35a88802559d
Ahora lo borraremos:
❯ docker rmi $(docker images -aq) --force
Untagged: debian:latest
Untagged: debian@sha256:45f2e735295654f13e3be10da2a6892c708f71a71be845818f6058982761a6d3
Deleted: sha256:2e5b8d3ef33ebde2b2a943fadb241a63de1535a007a7bd185e7037abfff99f63
Deleted: sha256:f6faf32734e0870d82ea890737958fe33ce9ddfed27b3b157576d2aadbab3322
Untagged: ubuntu:latest
Untagged: ubuntu@sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30
Deleted: sha256:35a88802559dd2077e584394471ddaa1a2c5bfd16893b829ea57619301eb3908
Deleted: sha256:a30a5965a4f7d9d5ff76a46eb8939f58e95be844de1ac4a4b452d5d31158fdea
❯ docker images -a
REPOSITORY TAG IMAGE ID CREATED SIZE
También podemos hacer “snapshots” de nuestros contenedores de docker:
Primero pillaremos el ID CONTAINER del contenedor activo que queramos hacer una snapshot:
❯ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e5b9bcc4bcf6 ubuntu "/bin/bash" 12 minutes ago Up 12 minutes competent_moser
Ahora emplearemos docker commit
con la siguiente estructura:
docker commit IDCONTAINER nombresnapshot:latest
Ahora lo emplearé para crear una snapshot de mi contenedor ubuntu:
❯ docker commit e5b9bcc4bcf6 snapshot1:latest
sha256:8d230ff6c31a853ed18423b3feed105cad8e448f665ee45e0f29702665fd66dc
Ahora si hacemos un docker images
podremos ver la imagen snapshot1
:
❯ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
snapshot1 latest 8d230ff6c31a 38 seconds ago 226MB
ubuntu latest 35a88802559d 7 weeks ago 78.1MB
📍Desplegar nuestro primer contenedor
Ya sabiendo como usar Docker a nivel básico vamos a desplegar nuestro primer contenedor, para ello podemos hacer:
❯ sudo docker pull ubuntu:latest
❯ docker pull ubuntu:latest
latest: Pulling from library/ubuntu
9c704ecd0c69: Pull complete
Digest: sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30
Status: Downloaded newer image for ubuntu:latest
docker.io/library/ubuntu:latest
Si ahora hacemos un docker images
podremos ver la imagen de ubuntu:latest
:
❯ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 35a88802559d 7 weeks ago 78.1MB
Ahora lo que haremos es iniciar nuestro contenedor:
❯ docker run -dit ubuntu
fc58d5436a6882d7a99172ae3df4b2a372b9809a7454e8a64a75bdf0aff261e1
Yo recomiendo para evitar problemas si tenemos más contenedores es iniciarlos por su IMAGE ID
:
❯ docker run -dit 35a88802559d
fc58d5436a6882d7a99172ae3df4b2a372b9809a7454e8a64a75bdf0aff261e1
Si hacemos un docker ps
podremos ver que se esta iniciando en segundo plano como bien le hemos indicado:
❯ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fc58d5436a68 ubuntu "/bin/bash" 42 seconds ago Up 40 seconds focused_mayer
Para obtener acceso a una bash del contedor pondremos:
❯ docker exec -it fc58d5436a68 bash
root@fc58d5436a68:/#
Aquí también le tendremos que indicar el CONTAINER ID
.
📗Recomendaciones al iniciar nuestro contenedor
Ya teniendo acceso a una bash del contenedor recomiendo actualizar el contenedor para evitar a futuro problemas al instalar dependencias:
root@fc58d5436a68:/# apt update -y && apt upgrade -y
⚙️Configuración de servicios
📌Iniciar servicio OpenSSH
Para instalar OpenSSH tendremos que poner lo siguiente:
root@fc58d5436a68:/# apt install ssh
Una vez ya tengamos ssh instalado pondremos lo siguiente para iniciar el servicio:
root@fc58d5436a68:/# service ssh start
* Starting OpenBSD Secure Shell server sshd [ OK ]
Para confirmar podemos hacerle un escaneo nmap y ver si lo tiene abierto:
❯ nmap -p- --open -n -Pn -vvv 172.17.0.2
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-07-28 06:42 EDT
Initiating ARP Ping Scan at 06:42
Scanning 172.17.0.2 [1 port]
Completed ARP Ping Scan at 06:42, 0.04s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 06:42
Scanning 172.17.0.2 [65535 ports]
Discovered open port 22/tcp on 172.17.0.2
Completed SYN Stealth Scan at 06:42, 1.05s elapsed (65535 total ports)
Nmap scan report for 172.17.0.2
Host is up, received arp-response (0.0000070s latency).
Scanned at 2024-07-28 06:42:07 EDT for 1s
Not shown: 65534 closed tcp ports (reset)
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 64
MAC Address: 02:42:AC:11:00:02 (Unknown)
Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 1.25 seconds
Raw packets sent: 65536 (2.884MB) | Rcvd: 65536 (2.621MB)
📌Iniciar servicio FTP
Para instalar FTP pondremos lo siguiente:
root@fc58d5436a68:/# apt install vsftpd
Una vez finalizada la instalación iniciaremos su servicio:
root@fc58d5436a68:/# service vsftpd start
* Starting FTP server vsftpd [ OK ]
❯ nmap -p- --open -n -Pn -vvv 172.17.0.2
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-07-28 06:47 EDT
Initiating ARP Ping Scan at 06:47
Scanning 172.17.0.2 [1 port]
Completed ARP Ping Scan at 06:47, 0.07s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 06:47
Scanning 172.17.0.2 [65535 ports]
Discovered open port 21/tcp on 172.17.0.2
Completed SYN Stealth Scan at 06:47, 0.98s elapsed (65535 total ports)
Nmap scan report for 172.17.0.2
Host is up, received arp-response (0.0000070s latency).
Scanned at 2024-07-28 06:47:51 EDT for 1s
Not shown: 65534 closed tcp ports (reset)
PORT STATE SERVICE REASON
21/tcp open ftp syn-ack ttl 64
MAC Address: 02:42:AC:11:00:02 (Unknown)
Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 1.19 seconds
Raw packets sent: 65536 (2.884MB) | Rcvd: 65536 (2.621MB)
Si por ejemplo queremos hacer una máquina donde está habilitado el anonymous tendremos que editar con nano que tendremos que instalarlo nosotros porque en el contenedor ubuntu no viene y con nano editaremos el /etc/vsftpd.conf
:
Instalamos nano:
apt install nano
Editamos el archivo vsftpd.conf y buscaremos la linea que ponga:
# Allow anonymous FTP? (Disabled by default).
anonymous_enable=NO
Y cambiaremos el anonymous_enable=NO
por:
anonymous_enable=YES
Guardamos y reiniciamos el servicio:
root@fc58d5436a68:/etc# service vsftpd restart
* Stopping FTP server [ OK ]
* Starting FTP server vsftpd [ OK ]
Ahora lanzaremos un nmap indicandole el script ftp-anon
:
❯ nmap -p21 --script=ftp-anon 172.17.0.2
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-07-28 06:54 EDT
Nmap scan report for 172.17.0.2
Host is up (0.000042s latency).
PORT STATE SERVICE
21/tcp open ftp
|_ftp-anon: Anonymous FTP login allowed (FTP code 230)
MAC Address: 02:42:AC:11:00:02 (Unknown)
Nmap done: 1 IP address (1 host up) scanned in 0.39 seconds
📌Iniciar servicio Apache2
Para instalar Apache2 pondremos lo siguiente:
root@fc58d5436a68:~# apt install apache2
Una vez finalizada la instalación iniciaremos el servicio:
root@fc58d5436a68:~# service apache2 start
* Starting Apache httpd web server apache2
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message*
Ahora si vamos a nuestro navegador y ponemos la IP del contenedor podremos ver la plantilla predeterminada de Apache2:
Si queremos modificar la web tendremos que ir al /var/www/html
y ahi dentro podremos meter una plantilla html o crear a mano la web:
En mi caso he modificado el index.html
:
<h1>Blog Pylon - Crea tu CTF en Docker<h1>
<p>Espero que te este gustando!!</p>
📌Iniciar servicio Nginx
Para instalar nginx pondremos lo siguiente:
root@fc58d5436a68:~# apt install nginx
Una vez finalizada la instalación vamos a iniciar el servicio:
root@fc58d5436a68:~# service nginx start
* Starting nginx nginx [ OK ]
Para modificar o crear la web usa la misma ruta que Apache2 que es la /var/www/html
.
📌Crear servicio personalizado
Hay a veces donde nos puede pasar que necesitemos crear un servicio personalizado, por ejemplo para un producto que se inicie en local mediante un script y no un servicio como apache2,nginx,ftp,ssh….
La estructura de un servicio es así:
[Unit]
Description=NombreServicio
After=network.target
[Service]
ExecStart=/ruta/al/ejecutable
WorkingDirectory=/ruta/al/directorio/del/ejecutable
Restart=always
User=usuario
Group=grupo
[Install]
WantedBy=multi-user.target
Vamos a crear un servicio personalizado que corra un servidor de python3 en el 8080, para ello primero instalaremos python3:
root@fc58d5436a68:~# apt install python3
Si hacemos un python3 -m http.server 8080
contemplaremos que se iniciara un servidor web por el 8080, así que lo tomaremos como de referencia. Para crear el servicio tendremos que ir a la siguiente ruta:
/etc/systemd/system
Y ahí dentro crearemos un archivo con la extension .service
, y dentro de ese archivo meteremos la estructura que he hemos visto anteriormente:
root@fc58d5436a68:/etc/systemd/system# cat personalizado.service
[Unit]
Description=NombreServicio
After=network.target
[Service]
ExecStart=/ruta/al/ejecutable
WorkingDirectory=/ruta/al/directorio/del/ejecutable
Restart=always
User=usuario
Group=grupo
[Install]
WantedBy=multi-user.target
Ahora cambiare los valores de Description
ExecStart
y WorkingDirectory
:
[Unit]
Description=serverpersonalizado
After=network.target
[Service]
ExecStart=/usr/bin/python3 -m http.server 8080 -d /var/www/html/
WorkingDirectory=/usr/bin/
Restart=always
User=root
Group=root
[Install]
WantedBy=multi-user.target
- Con el
-d
le indico el directorio, que en mi caso es el/var/www/html
.
Antes de iniciarlo instalaremos systemctl:
root@fc58d5436a68:/etc/systemd/system# apt install systemctl
Ahora haremos un daemon-reload
:
root@fc58d5436a68:/etc/systemd/system# systemctl daemon-reload
/usr/bin/systemctl:1541: SyntaxWarning: invalid escape sequence '\w'
expanded = re.sub("[$](\w+)", lambda m: get_env1(m), cmd.replace("\\\n",""))
/usr/bin/systemctl:1543: SyntaxWarning: invalid escape sequence '\w'
new_text = re.sub("[$][{](\w+)[}]", lambda m: get_env2(m), expanded)
/usr/bin/systemctl:1628: SyntaxWarning: invalid escape sequence '\w'
cmd3 = re.sub("[$](\w+)", lambda m: get_env1(m), cmd2)
/usr/bin/systemctl:1631: SyntaxWarning: invalid escape sequence '\w'
newcmd += [ re.sub("[$][{](\w+)[}]", lambda m: get_env2(m), part) ]
ERROR:systemctl: dbus.service: Executable path is not absolute, ignoring: @/usr/bin/dbus-daemon @dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
Podremos ver que nos da varios errores pero podremos iniciar el servicio sin ningun problema.
Ahora iniciaremos el servicio:
root@fc58d5436a68:/etc/systemd/system# systemctl start personalizado.service
/usr/bin/systemctl:1541: SyntaxWarning: invalid escape sequence '\w'
expanded = re.sub("[$](\w+)", lambda m: get_env1(m), cmd.replace("\\\n",""))
/usr/bin/systemctl:1543: SyntaxWarning: invalid escape sequence '\w'
new_text = re.sub("[$][{](\w+)[}]", lambda m: get_env2(m), expanded)
/usr/bin/systemctl:1628: SyntaxWarning: invalid escape sequence '\w'
cmd3 = re.sub("[$](\w+)", lambda m: get_env1(m), cmd2)
/usr/bin/systemctl:1631: SyntaxWarning: invalid escape sequence '\w'
newcmd += [ re.sub("[$][{](\w+)[}]", lambda m: get_env2(m), part) ]
❯ nmap -p- --open -n -Pn -vvv 172.17.0.2
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-07-28 07:32 EDT
Initiating ARP Ping Scan at 07:32
Scanning 172.17.0.2 [1 port]
Completed ARP Ping Scan at 07:32, 0.05s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 07:32
Scanning 172.17.0.2 [65535 ports]
Discovered open port 8080/tcp on 172.17.0.2
Completed SYN Stealth Scan at 07:32, 1.00s elapsed (65535 total ports)
Nmap scan report for 172.17.0.2
Host is up, received arp-response (0.0000070s latency).
Scanned at 2024-07-28 07:32:16 EDT for 1s
Not shown: 65534 closed tcp ports (reset)
PORT STATE SERVICE REASON
8080/tcp open http-proxy syn-ack ttl 64
MAC Address: 02:42:AC:11:00:02 (Unknown)
Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 1.20 seconds
Raw packets sent: 65536 (2.884MB) | Rcvd: 65536 (2.621MB)
Y podremos ver la web:
⚙️Configuración de usuarios
📌Crear usuarios nuevos
Para crear usuario nuevos podremos usar adduser
:
root@fc58d5436a68:~# adduser usuarionuevo
info: Adding user `usuarionuevo' ...
info: Selecting UID/GID from range 1000 to 59999 ...
info: Adding new group `usuarionuevo' (1001) ...
info: Adding new user `usuarionuevo' (1001) with group `usuarionuevo (1001)' ...
info: Creating home directory `/home/usuarionuevo' ...
info: Copying files from `/etc/skel' ...
New password:
Retype new password:
passwd: password updated successfully
Changing the user information for usuarionuevo
Enter the new value, or press ENTER for the default
Full Name []:
Room Number []:
Work Phone []:
Home Phone []:
Other []:
Is the information correct? [Y/n]
info: Adding new user `usuarionuevo' to supplemental / extra groups `users' ...
info: Adding user `usuarionuevo' to group `users' ...
📌Eliminar usuarios
Para eliminar un usuario podremos usar deluser
:
root@fc58d5436a68:~# deluser usuarionuevo
info: Removing crontab ...
info: Removing user `usuarionuevo' ...
⚙️Configuración de permisos
📌Establecer permisos sudoers a usuarios
Antes de todo tendremos que instalar sudo
:
root@fc58d5436a68:~# apt install sudo
Para establecer permisos sudoers
a un usuario tendremos que editar el /etc/sudoers
y bajaremos hasta la zona donde ponga:
# User privilege specification
root ALL=(ALL:ALL) ALL
Para especificar un permiso sudo, tendremos que seguir la siguiente estructura:
usuario ALL=(usuario o root[ALL:ALL]) /ruta/del/binario/o/lo/que/sea
Por ejemplo yo he creado un usuario llamado sudoersuser
que tenga la capacidad de usar nano
como root sin necesidad de su credencial:
# User privilege specification
root ALL=(ALL:ALL) ALL
sudoersuser ALL=(root) NOPASSWD: /usr/bin/nano
Si nos convertimos en el usuario y hacemos un sudo -l
podremos ver el permiso que le hemos especificado en el /etc/sudoers
:
sudoersuser@fc58d5436a68:~$ sudo -l
Matching Defaults entries for sudoersuser on fc58d5436a68:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
User sudoersuser may run the following commands on fc58d5436a68:
(root) NOPASSWD: /usr/bin/nano
📌Permisos en Apache2
Cuando creamos una web en apache2 puede ocurrir de que los usuarios puedan acceder a la carpeta images,js,db,etc...
. Para impedir esto tendremos que crear un archivo .conf
en el directorio de /etc/apache2/sites-enabled
, en el veremos un archivo llamado 000-default.conf
, lo editaremos y pondremos lo siguiente:
<Directory /var/www/html/images/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
<VirtualHost *:80>
# The ServerName directive sets the request scheme, hostname and port that
# the server uses to identify itself. This is used when creating
# redirection URLs. In the context of virtual hosts, the ServerName
# specifies what hostname must appear in the request's Host: header to
# match this virtual host. For the default virtual host (this file) this
# value is not decisive as it is used as a last resort host regardless.
# However, you must set it for any further virtual host explicitly.
#ServerName www.example.com
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
<Directory /var/www/html/images/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# For most configuration files from conf-available/, which are
# enabled or disabled at a global level, it is possible to
# include a line for only one particular virtual host. For example the
# following line enables the CGI configuration for this host only
# after it has been globally disabled with "a2disconf".
#Include conf-available/serve-cgi-bin.conf
</VirtualHost>
Ahora guardaremos esos cambios y reiniciaremos el servicio apache2:
root@e5b9bcc4bcf6:/var/www/html/images# service apache2 restart
* Restarting Apache httpd web server apache2
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
Y todo esto lo podemos configurar para diferentes carpetas:
<Directory /var/www/html/images/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
<Directory /var/www/html/css/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
<Directory /var/www/html/js/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
⚙️ Configuración de Dockerfile
Ya estamos casi por el final de nuestro CTF, ahora nos toca crear un Dockerfile apuntando a una snapshot o directamente al contenedor docker de la siguiente manera:
FROM snapshot1:latest
Ahora pondremos CMD
y le indicaremos ejecutar todos los servicios que tienen que estar activos cuando se despliege nuestro contenedor docker:
FROM snapshot1:latest
CMD service apache2 start && tail -f /dev/null
Veréis que al final de los servicios he puesto tail -f /dev/null
esto lo que hace es un bucle infinito apuntando al /dev/null, esto nos ayudara a cuando la persona inicie el contenedor docker los servicios no se apaguen y estén iniciados.
📌 Exportar contenedor a .tar
Esta es una de las partes más importantes si queremos publicar el CTF en la plataforma de Dockerlabs que es que tendremos que construir una nueva imagen con el Dockerfile que hemos creado con los parámetros indicados de iniciar los servicios necesarios, así que vamos a construir una imagen nueva desde el Dockerfile llamada miprimerctf
claramente no es necesario poner ese nombre, vosotros poner el que más os guste para el CTF:
Emplearemos docker build
y el parametro --tag
para establecerle un nombre a la imagen:
❯ docker build --tag miprimerctf .
Sending build context to Docker daemon 282.1kB
Step 1/2 : FROM snapshot1:latest
---> 8d230ff6c31a
Step 2/2 : CMD service apache2 start && tail -f /dev/null
---> Running in a2c8c3cd1aba
Removing intermediate container a2c8c3cd1aba
---> d0ba19aba1c4
Successfully built d0ba19aba1c4
Successfully tagged miprimerctf:latest
El .
es que le estoy indicando que el archivo Dockerfile se encuentra en el directorio actual donde estoy. Si hacemos un docker images
podremos ver la imagen que hemos construido con su respectivo nombre:
❯ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
miprimerctf latest d0ba19aba1c4 About a minute ago 226MB
snapshot1 latest 8d230ff6c31a 10 minutes ago 226MB
ubuntu latest 35a88802559d 7 weeks ago 78.1MB
Ahora es cuando emplearemos docker save
para guardar la imagen en un .tar:
❯ docker save -o miprimerctf.tar miprimerctf:latest
❯ ls
Dockerfile miprimerctf.tar
Para comprobar de que todo funciona correcto vamos a descargarnos una maquina al azar de Dockerlabs y utilizaremos su auto_deploy.sh
a nuestro archivo .tar
:
❯ bash auto_deploy.sh miprimerctf.tar
## .
## ## ## ==
## ## ## ## ===
/""""""""""""""""\___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\______/
___ ____ ____ _ _ ____ ____ _ ____ ___ ____
| \ | | | |_/ |___ |__/ | |__| |__] [__
|__/ |__| |___ | \_ |___ | \ |___ | | |__] ___]
Se han detectado máquinas de DockerLabs previas, debemos limpiarlas para evitar problemas, espere un momento...
Se han detectado máquinas de DockerLabs previas, debemos limpiarlas para evitar problemas, espere un momento...
Estamos desplegando la máquina vulnerable, espere un momento.
Máquina desplegada, su dirección IP es --> 172.17.0.3
Presiona Ctrl+C cuando termines con la máquina para eliminarla
Ahora le haremos un escaneo nmap para ver si esta el puerto 80 abierto que es el que hemos establecido iniciando el servidor apache2 en el Dockerfile:
❯ nmap -p- --open -n -Pn -vvv 172.17.0.3
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-07-28 10:15 EDT
Initiating ARP Ping Scan at 10:15
Scanning 172.17.0.3 [1 port]
Completed ARP Ping Scan at 10:15, 0.06s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 10:15
Scanning 172.17.0.3 [65535 ports]
Discovered open port 80/tcp on 172.17.0.3
Completed SYN Stealth Scan at 10:15, 1.11s elapsed (65535 total ports)
Nmap scan report for 172.17.0.3
Host is up, received arp-response (0.0000070s latency).
Scanned at 2024-07-28 10:15:50 EDT for 1s
Not shown: 65534 closed tcp ports (reset)
PORT STATE SERVICE REASON
80/tcp open http syn-ack ttl 64
MAC Address: 02:42:AC:11:00:03 (Unknown)
Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 1.31 seconds
Raw packets sent: 65536 (2.884MB) | Rcvd: 65536 (2.621MB)
📝 Creación del Writeup
Ya habiendo comprobado que la máquina funciona bien y está todo correcto, nos toca lo último que es el writeup. Os comparto una estructura en PDF de un writeup para Dockerlabs que es el que yo empleo:
El template esta basado en el oficial de HackTheBox.
👋 Despedida
Espero que hayáis aprendido en como crear un CTF en Docker, tener en cuenta que ciertas cosas como los servicios se puede hacer en un Ubuntu Server y intentar crear una máquina para otra plataforma. Este es un blog que me ha parecido muy bueno crearlo para ayudar a la gente que quiere crear su CTF sin tener idea y obtenga cierta base con este blog. Adelanto que subiré un blog nuevo donde ensenaré como configuro una máquina desde el minuto 0 hasta que la tengo creada.
Att: Pylon