La CVE-2024-29415 est une vulnérabilité de type Server-Side Request Forgery (SSRF) qui découle de la CVE-2023-42282 mais qui a pourtant comme un effet de déjà vu.
Le paquet ip, jusqu'à la version 2.0.1 pour Node.js, pourrait permettre une attaque de type SSRF (Server-Side Request Forgery), car certaines adresses IP (telles que 127.1, 01200034567, 012.1.2.3, 000:0:0000::01 et ::fFFf:127.0.0.1) sont incorrectement classées comme globalement routables par la fonction isPublic(). Cette vulnérabilité est due à une correction incomplète de la CVE-2023-42282.
Préambule
Cette vulnérabilité fait directement suite à la CVE-2023-42282comme étant une correction incomplète. Toutefois, la situation semble plus complexe qu'il n'y paraît, car la version 2.0.0 s'apparente davantage à un retour en arrière (et est donc similaire à la version 1.1.8), tandis que la version 2.0.1 semble implémenter le même correctif que la version 1.1.9.
Analyse de la vulnérabilité
L'analyse de la version 2.0.0 révèle l'absence des modifications introduites dans la version 1.1.9. Ainsi, cette version se rapproche de la 1.1.8, à quelques différences près liées à la déclaration, à l'initialisation ou à l'utilisation de certaines variables. Surtout, la fonction isPrivate(), et dans une moindre mesure isPublic(), ne bénéficient d'aucune correction :
La version 2.0.0 présente donc la même vulnérabilité que la version 1.1.8, liée à la CVE-2023-42282.
L'analyse de la version 2.0.1 met en évidence la même correction que celle apportée en version 1.1.9, tout en intégrant également les modifications liées à la définition, à l'initialisation et à l'utilisation des variables.
// Version 1.1.9
ip.isPrivate = function (addr) {
// check loopback addresses first
if (ip.isLoopback(addr)) {
return true;
}
// ensure the ipv4 address is valid
if (!ip.isV6Format(addr)) {
const ipl = ip.normalizeToLong(addr);
if (ipl < 0) {
throw new Error('invalid ipv4 address');
}
// normalize the address for the private range checks that follow
addr = ip.fromLong(ipl);
}
// check private ranges
return /^(::f{4}:)?10\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr)
|| /^(::f{4}:)?192\.168\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr)
|| /^(::f{4}:)?172\.(1[6-9]|2\d|30|31)\.([0-9]{1,3})\.([0-9]{1,3})$/i
.test(addr)
|| /^(::f{4}:)?169\.254\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr)
|| /^f[cd][0-9a-f]{2}:/i.test(addr)
|| /^fe80:/i.test(addr)
|| /^::1$/.test(addr)
|| /^::$/.test(addr);
};
ip.isPublic = function (addr) {
return !ip.isPrivate(addr);
};
// Version 2.0.1
ip.isPrivate = function (addr) {
// check loopback addresses first
if (ip.isLoopback(addr)) {
return true;
}
// ensure the ipv4 address is valid
if (!ip.isV6Format(addr)) {
const ipl = ip.normalizeToLong(addr);
if (ipl < 0) {
throw new Error('invalid ipv4 address');
}
// normalize the address for the private range checks that follow
addr = ip.fromLong(ipl);
}
// check private ranges
return /^(::f{4}:)?10\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr)
|| /^(::f{4}:)?192\.168\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr)
|| /^(::f{4}:)?172\.(1[6-9]|2\d|30|31)\.([0-9]{1,3})\.([0-9]{1,3})$/i
.test(addr)
|| /^(::f{4}:)?169\.254\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr)
|| /^f[cd][0-9a-f]{2}:/i.test(addr)
|| /^fe80:/i.test(addr)
|| /^::1$/.test(addr)
|| /^::$/.test(addr);
};
ip.isPublic = function (addr) {
return !ip.isPrivate(addr);
};
Ainsi, la version 2.0.1 présente les mêmes faiblesses que la version 1.1.9 en raison d'un correctif incomplet de la CVE-2023-42282.