Cryptographic Failures
Java 8 · Servlet · JSP
Mots de passe hashés en MD5 sans sel. IBAN stockés en clair. Clés de chiffrement codées en dur.
A04:2025 - Cryptographic Failures
ansible-playbook -i inventory.ini playbook.yml --tags switch -e project=04
ansible-playbook -i inventory.ini playbook.yml --tags switch -e project=04 -e variant=secure
Référence OWASP
TODO
démos vidéo
pas de démo pour ce projet
Vue d'ensemble
Ce module illustre les defaillances cryptographiques (anciennement "Sensitive Data Exposure"), categorie A04 du classement OWASP Top 10 2025.
L'application simule un portail assure qui permet la connexion et l'affichage du profil (incluant les coordonnees bancaires IBAN).
Note : La vulnérabilité liée au cookie de session sans flag
HttpOnlya été extraite dans le module 12-a02-a05-2025, qui lui est entièrement dédié (A02:2025 + A05:2025).
Les 2 vulnerabilites demonstrees
Vulnerabilite 1 : Hachage MD5 sans sel pour les mots de passe
Code vulnerable (vulnerable/) :
// AuthService.java - vulnerable
public String hashPassword(String password) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] hash = md.digest(password.getBytes(StandardCharsets.UTF_8));
return DatatypeConverter.printHexBinary(hash).toLowerCase();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
Problemes :
- MD5 est un algorithme de hachage rapide, pas concu pour les mots de passe
- Absence de sel : deux utilisateurs avec le meme mot de passe ont le meme hash
- Vulnerable aux attaques par rainbow table et dictionnaire
- MD5 est considere comme cryptographiquement casse depuis 2004
Base de donnees vulnerable :
jdupont | 7c6a180b36896a65c4c80d592e87e3be (= MD5("password1"))
mmartin | [hash MD5 de Assur@nce2024!]
pdurand | 7c6a180b36896a65c4c80d592e87e3be (= meme hash que jdupont !)
Vulnerabilite 2 : IBAN stocke en clair dans la base de donnees
Code vulnerable :
// DatabaseInit.java - vulnerable
pstmt.setString(5, "FR7612345678901234567890123"); // IBAN en clair !
// profil.jsp - vulnerable
<p>IBAN : ${assure.iban}</p> <!-- Affiche directement depuis la BDD -->
Problemes :
- Une compromission de la base de donnees expose directement toutes les coordonnees bancaires
- Violation du RGPD (donnees financieres = donnees sensibles)
- Pas de protection en cas de dump SQL ou acces non autorise a la BDD
Exploitation etape par etape
Exploit 1 : Cassage MD5 par rainbow table
Prerequis : Acces a la table assures (dump BDD, injection SQL, etc.)
-
Recuperer les hashes MD5 de la BDD :
SELECT login, password_hash FROM assures; -- Resultat : -- jdupont | 7c6a180b36896a65c4c80d592e87e3be -- pdurand | 7c6a180b36896a65c4c80d592e87e3be -
Utiliser le script de cassage fourni :
Linux/Mac :
chmod +x exploit/crack-md5.sh ./exploit/crack-md5.sh 7c6a180b36896a65c4c80d592e87e3be # [+] MOT DE PASSE TROUVE ! # Hash : 7c6a180b36896a65c4c80d592e87e3be # Mot de passe : password1Windows :
exploit\crack-md5.bat 7c6a180b36896a65c4c80d592e87e3be -
Constater que
jdupontetpdurandont le meme hash (meme mot de passe), ce qui est visible directement dans la BDD ! -
Se connecter avec les identifiants recuperes :
jdupont/password1
Via la console H2 (accessible sur /h2-console) :
JDBC URL : jdbc:h2:mem:assuriadb
Utilisateur : sa
Mot de passe : (vide)
SELECT login, password_hash, iban FROM assures;
Exploit 2 : Lecture des IBANs en clair
- Acceder a la console H2 :
https://appsec.cc/h2-console - Se connecter avec
jdbc:h2:mem:assuriadb(user:sa, pass: vide) - Executer :
SELECT login, iban FROM assures; - Tous les IBANs sont visibles en clair :
JDUPONT | FR7612345678901234567890123 MMARTIN | FR7698765432109876543210987 PDURAND | FR7611112222333344445555666
Les 2 corrections appliquees dans secure/
Correction 1 : BCrypt avec sel pour les mots de passe
// AuthService.java - securise
public String hashPassword(String password) {
return BCrypt.hashpw(password, BCrypt.gensalt(12));
}
public boolean verifyPassword(String password, String hash) {
return BCrypt.checkpw(password, hash);
}
Pourquoi BCrypt ?
- Integre un sel aleatoire automatiquement (elimine les attaques rainbow table)
- Facteur de cout parametrable (12 = ~300ms de calcul, rend les attaques brute-force tres lentes)
- Concu specifiquement pour le hachage de mots de passe
- Chaque hash est unique meme pour des mots de passe identiques
Exemple de hash BCrypt :
$2a$12$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
Format : $2a$ + cout + $ + sel (22 chars) + hash (31 chars)
Correction 2 : Chiffrement AES/GCM des IBANs
// CryptoService.java - securise
// Algorithme : AES/GCM/NoPadding
// IV : 12 octets aleatoires (SecureRandom)
// Tag GCM : 128 bits
// Cle : 256 bits depuis variable d'environnement ASSURIA_ENCRYPTION_KEY
public String encrypt(String plaintext) throws Exception {
byte[] iv = new byte[12];
new SecureRandom().nextBytes(iv);
// ... chiffrement AES/GCM ...
// Retourne Base64(IV + ciphertext)
}
Pourquoi AES/GCM ?
- Chiffrement authentifie : detecte toute modification du ciphertext (integrite)
- IV aleatoire unique par chiffrement : deux chiffrements du meme texte donnent des resultats differents
- Cle externe : meme avec un dump BDD, les donnees sont illisibles sans la cle
- Standard recommande par NIST pour le chiffrement symetrique
Configuration :
# Generer une cle de 32 octets et l'encoder en Base64
export ASSURIA_ENCRYPTION_KEY=$(openssl rand -base64 32)
mvn compile exec:java
Comment lancer les applications
Version vulnerable
cd vulnerable
mvn compile exec:java
Application disponible sur : https://appsec.cc
Console H2 (BDD exposee) : https://appsec.cc/h2-console
- JDBC URL :
jdbc:h2:mem:assuriadb - Utilisateur :
sa - Mot de passe : (laisser vide)
Version securisee
cd secure
# Optionnel : definir une vraie cle de chiffrement
export ASSURIA_ENCRYPTION_KEY=$(openssl rand -base64 32)
# Sur Windows :
# for /f %i in ('powershell -Command "[Convert]::ToBase64String([System.Security.Cryptography.RandomNumberGenerator]::GetBytes(32))"') do set ASSURIA_ENCRYPTION_KEY=%i
mvn compile exec:java
Application disponible sur : https://appsec.cc
Note : La console H2 est desactivee dans la version securisee.
Utilisateurs de test
| Login | Mot de passe | IBAN |
|---|---|---|
| jdupont | password1 | FR7612345678901234567890123 |
| mmartin | Assur@nce2024! | FR7698765432109876543210987 |
| pdurand | password1 | FR7611112222333344445555666 |
Lecons de securite cles
1. Ne jamais utiliser MD5/SHA1 pour les mots de passe
Les algorithmes de hachage generiques (MD5, SHA-1, SHA-256) sont trop rapides pour les mots de passe. Utiliser BCrypt, Argon2 ou scrypt.
2. Toujours chiffrer les donnees sensibles au repos
Les donnees personnelles sensibles (IBAN, numero de carte, numero de secu) doivent etre chiffrees en base de donnees. Une compromission de la BDD ne doit pas exposer directement les donnees.
3. Ne pas exposer la console de base de donnees en production
La console H2 (ou pgAdmin, phpMyAdmin, etc.) ne doit jamais etre accessible en production. Elle permet un acces direct et potentiellement dangereux a la BDD.
4. Gerer les cles de chiffrement via des variables d'environnement
Les cles cryptographiques ne doivent jamais etre en dur dans le code source. Utiliser des variables d'environnement, un vault (HashiCorp Vault, AWS KMS), ou un gestionnaire de secrets.
5. Principe de moindre privilege pour les IBANs
En production, afficher les IBANs masques par defaut (FR76 **** **** ****)
et ne reveler le numero complet qu'apres une confirmation explicite de l'utilisateur.
Structure du projet
04-cryptographic-failures/
├── README.md (ce fichier)
├── exploit/
│ ├── rainbow-table.txt (hashes MD5 courants)
│ ├── crack-md5.sh (script de cassage Linux/Mac)
│ └── crack-md5.bat (script de cassage Windows)
├── vulnerable/ (application Java vulnerable)
│ └── src/main/
│ ├── java/cc/appsec/crypto/
│ │ ├── Main.java
│ │ ├── model/Assure.java
│ │ ├── db/DatabaseInit.java
│ │ ├── service/AuthService.java
│ │ ├── dao/AssureDao.java
│ │ └── servlet/{Login,Profil,Logout}Servlet.java
│ └── webapp/
│ ├── index.jsp
│ └── WEB-INF/
│ ├── web.xml
│ └── jsp/{login,profil}.jsp
└── secure/ (application Java securisee)
└── src/main/
├── java/cc/appsec/crypto/
│ ├── Main.java
│ ├── model/Assure.java
│ ├── db/DatabaseInit.java
│ ├── service/{Auth,Crypto}Service.java
│ ├── dao/AssureDao.java
│ └── servlet/{Login,Profil,Logout}Servlet.java
└── webapp/
├── index.jsp
└── WEB-INF/
├── web.xml
└── jsp/{login,profil}.jsp