Neutron, notre moteur d’IA, a obtenu un score de 97,1 % sur le benchmark CyberGym de l’UC Berkeley. En savoir plus

Analyse approfondie

Analyse approfondie

RCE TightVNC Viewer avant authentification, corrigée dans 2.8.90

Un serveur VNC malveillant exécute du code sur le Viewer TightVNC avant toute demande de mot de passe ; passez le Viewer en 2.8.90 et fermez le mode écoute.

TL;DR

  • Le Viewer TightVNC pour Windows tronque à 32 bits la taille de son tampon de pixels. Un serveur VNC malveillant qui annonce un écran énorme peut donc exécuter du code sur le viewer avant toute demande de mot de passe. SSD Secure Disclosure a publié la faille avec un exploit fonctionnel le 29 octobre 2026.
  • Tout Viewer antérieur à 2.8.89 sur la ligne 2.8 est concerné ; le chercheur a démontré l'exploit sur 2.8.88 x64. Les postes d'assistance qui utilisent le mode écoute exposent le viewer sur TCP 5500 sans mot de passe ni restriction d'IP, ce qui en fait une exécution de code à distance avant authentification.
  • L'éditeur a corrigé le viewer en 2.8.89 et 2.8.90, publiées le 2 et le 5 octobre 2026, et recommande 2.8.90. Aucun CVE n'est attribué, aucun avis éditeur n'existe, et aucune exploitation n'est connue ; la faille n'est pas au catalogue KEV de la CISA au 2 novembre 2026.
  • Mettez à jour chaque Viewer TightVNC en 2.8.90. En attendant, désactivez le mode écoute ou restreignez TCP 5500 aux hôtes de confiance, et ne pointez jamais le viewer vers un serveur inconnu ; aucune restriction réseau ne couvre cette seconde voie.

Suis-je concerné ?

Vous êtes exposé lorsque toutes ces conditions sont réunies :

  • La machine exécute le Viewer TightVNC pour Windows, en version 2.8.88 ou toute version antérieure de la ligne 2.8. Le chercheur a démontré l'exploit sur 2.8.88 x64, et les vérifications qui l'arrêtent apparaissent d'abord en 2.8.89.
  • L'une des deux voies d'attaque est atteignable. En mode écoute, lancé par tvnviewer.exe -listen ou depuis le menu de la barre système, le viewer écoute sur 0.0.0.0:5500 et accepte tout serveur qui se connecte, sans mot de passe ni restriction d'IP. Par ailleurs, un utilisateur qui connecte le viewer à un serveur malveillant ou compromis est compromis à la connexion, avant la demande de mot de passe.
  • L'attaquant peut atteindre le port 5500, pour la voie en écoute, ou peut faire tourner ou détourner un serveur VNC auquel le viewer se connectera.
Branche Versions concernées Version corrigée
TightVNC 2.8.x jusqu'à 2.8.88 2.8.90 (2.8.89 en fermait une partie)
TightVNC 2.8.x sur hôtes d'ère Windows XP jusqu'à 2.8.88 2.8.90, dernière ligne qui gère encore XP
TightVNC 4.x sans avis ; publiée après les correctifs sans objet ; version actuelle 4.0.2 (28 octobre 2026)

Le Viewer 2.8.88 est sorti le 19 juin 2026, donc au 2 novembre 2026 le code concerné était livré depuis 136 jours sur les installations récentes ; les installations plus anciennes le portent plus longtemps. La divulgation décrit le mode écoute comme « le déploiement habituel des postes d'assistance », ce qui fait de la voie en écoute l'exposition pratique.

Vérifiez la version installée du viewer et s'il écoute :

(Get-Item "C:\Program Files\TightVNC\tvnviewer.exe").VersionInfo.FileVersion
netstat -ano | findstr :5500

La première commande affiche la version du viewer sur une installation par défaut ; ajustez le chemin si TightVNC est installé ailleurs. La seconde affiche tout socket local en écoute sur TCP 5500, c'est-à-dire le mode écoute exposé ; un résultat vide signifie que cette voie est fermée.

Comment corriger ?

Mettez à jour chaque Viewer TightVNC en 2.8.90 :

  1. Téléchargez l'installateur 2.8.90 de votre plateforme depuis la page de téléchargement de l'éditeur et exécutez-le ; il remplace le viewer en place.
  2. Confirmez le correctif avec la vérification de version ci-dessus ; la version de fichier doit indiquer 2.8.90.
  3. Redémarrez tout viewer qui tourne en mode écoute, pour que le nouveau binaire soit celui lié au port 5500.

L'avis de version de l'éditeur pour 2.8.90 indique que les versions 2.8.89 et 2.8.90 « corrigent plusieurs problèmes de sécurité du Viewer » et recommande vivement 2.8.90. En attendant la mise à jour, deux mesures resserrent l'exposition, et toutes deux ont des limites :

  1. Désactivez le mode écoute sur les postes d'assistance, ou restreignez TCP 5500 au pare-feu aux adresses des serveurs VNC de confiance. La limite est claire : la faille reste dans le viewer, et tout chemin non fiable vers 5500 la laisse ouverte.
  2. Demandez aux opérateurs de ne jamais connecter le viewer à un serveur qu'ils ne contrôlent pas. Aucune restriction réseau ne couvre cette voie, car la connexion est sortante.

Quelle est la cause racine ?

Le viewer dimensionne son tampon de pixels à partir d'un résultat 32 bits tronqué. Ses écritures utilisent ensuite des décalages dérivés des dimensions complètes annoncées par le serveur. Le code se trouve dans FrameBuffer, dans la couche rfb du viewer, cité depuis la distribution source 2.8.88.

Le calcul de taille multiplie en 64 bits puis jette tout ce qui dépasse 32 :

int FrameBuffer::getBufferSize() const
{
  return (int)((UINT64)m_dimension.area() * m_pixelFormat.bitsPerPixel / 8);
}

bool FrameBuffer::resizeBuffer()
{
  if (m_buffer != 0) {
    delete []m_buffer;
  }
  if ((m_buffer = new UINT8[getBufferSize()]) == 0) {
    return false;
  }
  return true;
}

Un serveur qui annonce un écran de 32768 sur 32769 à 32 bits par pixel fait déborder le produit. Le produit 64 bits dépasse 4 Go, le cast (int) garde 128 Ko, et le viewer alloue 128 Ko. Les dimensions stockées conservent les 32768 sur 32769 annoncées, donc la toile logique et l'allocation divergent d'exactement 2^32 octets (4 294 967 296).

Le décalage d'écriture est ensuite calculé dans un int 32 bits signé, sur la largeur annoncée, sans aucune comparaison avec ce qui a été alloué :

void *FrameBuffer::getBufferPtr(int x, int y) const
{
  char *ptr = (char *)m_buffer;
  ptr += (y * m_dimension.width + x) * getBytesPerPixel();

  return (void *)ptr;
}

Un y élevé fait déborder le produit et l'étend avec son signe, donc un rectangle de mise à jour d'écran peut placer ses pixels à n'importe quel décalage choisi du tampon, positif ou négatif. Les mises à jour arrivent du serveur comme des rectangles Raw ou Tight, via RemoteViewerCore::receiveFbUpdateRectangle vers les décodeurs, et le protocole RFB laisse le serveur choisir aussi bien la géométrie que chaque rectangle.

Comment la faille est-elle exploitée ?

L'exploit publié n'a besoin que d'une connexion et d'aucun identifiant :

  1. Le serveur RFB de l'attaquant salue le viewer et propose un seul type de sécurité, None. L'authentification RFB est unidirectionnelle, le serveur ne se prouve jamais au viewer, et le viewer TightVNC accepte None.
  2. Le ServerInit annonce la géométrie empoisonnée, 32768 sur 32769 à 32 bits par pixel. La poignée de main fait 45 octets et alloue le tampon de 128 Ko que l'exploit appelle FB1.
  3. Un rectangle Raw aux coordonnées (7492, 32767) atterrit à FB1 - 0x18AF0, c'est-à-dire le champ m_dataLength d'un objet BufferedOutputStream situé sous le framebuffer. L'exploit y écrit une valeur élevée.
s.sendall(b"RFB 003.008\n")                 # greet as the server
s.sendall(bytes([1, 1]))                    # offer one security type: None
s.sendall(struct.pack(">I", 0))             # SecurityResult = OK
s.sendall(struct.pack(">HH", 32768, 32769)  # ServerInit: the poisoned geometry
          + PIXEL_FORMAT + struct.pack(">I", 3) + b"PWN")
  1. Le flush() suivant renvoie environ 100 Ko de tas adjacent par le socket. L'exploit en déduit la base d'image de tvnviewer.exe et l'adresse du framebuffer, ce qui vainc la randomisation de l'espace d'adressage.
  2. L'exploit écrit un objet factice et une chaîne de programmation orientée retour dans le framebuffer de 128 Ko, puis écrase le pointeur de vtable du BufferedOutputStream. Le prochain appel virtuel suit l'objet factice, fait pivoter la pile vers le framebuffer, et la chaîne se termine par CreateProcessW.

L'exploit fonctionne contre un viewer récent, dans sa configuration par défaut, avec ASLR et DEP activés ; le control-flow guard est absent du binaire. La divulgation publie le script d'exploit complet pour les deux voies d'attaque, le viewer en écoute et la connexion sortante, avec un mode de relance qui restaure le viewer après chaque exécution.

Comment l'attaque se déroule-t-elle ?

Il suffit à l'attaquant que le viewer accepte une session, et l'allocation tronquée transforme cette session en contrôle du processus du viewer.

flowchart LR A["L'attaquant fait tourner un
serveur RFB malveillant"] --> B["Le viewer accepte,
type de sécurité None"] B --> C["ServerInit annonce
32768 x 32769 à 32 bpp"] C --> D["Tampon dimensionné en 32 bits,
4 Go de toile sur 128 Ko,
sans vérification des limites"] D --> E["Les rectangles écrivent
hors de l'allocation"] E --> F["Fuite de tas, détournement de vtable,
ROP vers CreateProcessW :
code sur le viewer"]

Que peut faire un attaquant ?

L'impact démontré est une exécution de code dans le processus du viewer, sous le compte qui le lance, au moment où la session s'ouvre :

  • En mode écoute, tout hôte qui atteint TCP 5500 l'obtient sans mot de passe, sans liste d'adresses autorisées et sans intervention de l'opérateur. La divulgation décrit ce mode comme le déploiement habituel des postes d'assistance, donc la population exposée est l'outillage d'assistance, pas les serveurs.
  • Sur une connexion sortante, la compromission survient à la connexion, avant toute demande de mot de passe, donc les mots de passe VNC côté serveur ne protègent pas contre un serveur détourné.
  • L'exploit peut masquer la fenêtre de sa charge avec CREATE_NO_WINDOW, relancer le viewer après exécution, et faire planter le viewer à volonté en déni de service.

Les conditions sont étroites : l'attaquant doit être le serveur auquel le viewer parle, ou atteindre un viewer en écoute. Un serveur TightVNC, tvnserver, n'est pas la cible ici ; le sens de l'attaque est le point clé, la machine aidée attaquant la machine qui aide.

Pourquoi le correctif fonctionne-t-il ?

Le code source 2.8.89 ajoute un fichier, viewer-core/ViewerBufferSize.h, avec des prédicats de taille 64 bits, et valide les annonces du serveur avant toute allocation :

inline bool fitsFrameBuffer(int width, int height, int bytesPerPixel)
{
  if (width < 0 || height < 0 || bytesPerPixel <= 0) {
    return false;
  }

  const UINT64 alignedWidth = (static_cast<UINT64>(width) + 3) & ~static_cast<UINT64>(3);
  const UINT64 alignedHeight = (static_cast<UINT64>(height) + 3) & ~static_cast<UINT64>(3);
  return alignedWidth * alignedHeight <= INT_MAX / bytesPerPixel;
}

RemoteViewerCore::setFbProperties, qui consomme la géométrie du ServerInit, la rejette désormais d'emblée :

  if (!ViewerBufferSize::fitsFrameBuffer(width, height, bitsPerPixel / 8)) {
    throw Exception(_T("Framebuffer is too large"));
  }

Le même motif protège le chemin du curseur enrichi, et en 2.8.89 le décodeur Tight rejette aussi les rectangles JPEG surdimensionnés. En 2.8.90, le décodeur Tight ajoute deux vérifications : il rejette les données décompressées dont la taille ne correspond pas au rectangle déclaré, et les blocs compressés vides. Ce sont les « plusieurs problèmes de sécurité du Viewer » nommés par l'avis de version de l'éditeur.

Le correctif est complet pour les voies démontrées. Aucune annonce de serveur ne peut plus atteindre l'allocation tronquée, car la géométrie est validée à la frontière du protocole avant le dimensionnement du tampon. L'arithmétique tronquante reste dans FrameBuffer::getBufferSize, inchangée en 2.8.90, donc la sécurité dépend désormais de la validation en amont de chaque appelant. C'est un resserrement à une voie d'entrée validée, pas l'élimination de la classe de bug.

Comment savoir si j'ai été compromis ?

La divulgation ne publie pas d'indicateurs de compromission. Les traces de l'attaquant sont sur l'hôte du viewer, et chaque vérification ci-dessous découle de la mécanique publiée :

Get-WinEvent -LogName Application | Where-Object { $_.Message -match "tvnviewer" } | Select -First 20

Des plantages inexpliqués du viewer dans le journal applicatif marquent la variante par déni de service. La charge de l'exploit tourne en enfant du viewer, donc vérifiez la télémétrie de création de processus pour tout processus dont le parent est tvnviewer.exe. Sur les hôtes avec Sysmon, l'événement ID 1 avec ce parent est la requête.

Sur les viewers en écoute, passez en revue les journaux réseau pour des connexions entrantes vers TCP 5500 suivies d'un flot sortant du viewer d'environ 100 Ko. Ce flot est la fuite de tas que l'exploit relit.

Si un viewer était exposé et présente un de ces signes, considérez le compte de l'opérateur comme compromis et révoquez tout ce que ce compte pouvait atteindre.

Chronologie

  • 2026-06-19 : TightVNC 2.8.88, la version concernée démontrée, est publiée.
  • 2026-10-02 : TightVNC 2.8.89 livre des vérifications pour les framebuffers surdimensionnés, les mises à jour RichCursor et les rectangles JPEG Tight ; l'éditeur recommande la mise à jour.
  • 2026-10-05 : TightVNC 2.8.90 livre les correctifs restants du viewer, validant les tailles décompressées et rejetant les blocs compressés vides ; le code source porte cette date.
  • 2026-10-29 : SSD Secure Disclosure publie l'analyse et l'exploit, créditant SeongJoon Cho de SSD Labs Korea, et indique que l'éditeur n'a jamais répondu au rapport.
  • 2026-11-02 : aucun CVE n'est attribué, aucun avis éditeur n'est publié, et aucune exploitation n'est connue ; la faille n'est pas au catalogue KEV de la CISA.

Les correctifs sont sortis 105 jours après la version concernée 2.8.88 et 24 jours avant la publication de l'exploit
Figure 1 : la version concernée du 19 juin, les deux correctifs des 2 et 5 octobre, et l'exploit public du 29 octobre. Source : notes de version tightvnc.com et SSD Secure Disclosure, consultés le 2 novembre 2026

FAQ

Le serveur TightVNC est-il aussi concerné ?

Non. La cible est le Viewer, tvnviewer.exe, et l'attaque va du serveur vers le viewer. Un hôte qui ne fait tourner que le serveur TightVNC n'est exposé que dans la mesure où ses opérateurs utilisent aussi le viewer pour se connecter.

Un mot de passe VNC arrête-t-il cela ?

Non. Le viewer accepte le type de sécurité None, et l'authentification RFB ne prouve jamais l'identité du serveur au viewer. La voie sortante se complète avant toute demande de mot de passe, donc un mot de passe fort sur le vrai serveur ne sert plus rien dès que ce serveur est celui de l'attaquant.

Cette classe a-t-elle déjà frappé TightVNC ?

Oui, deux fois, chaque fois depuis un serveur malveillant. TightVNC 1.3.10 corrigeait des dépassements d'entier du viewer signalés par Core Security Technologies, qui laissaient un serveur VNC modifié corrompre le tas du viewer. La version 2.8.63 corrigeait un dépassement de tampon qui laissait un serveur « malveillant » exécuter du code sur la machine du viewer. Les notes de version de l'éditeur consignent les deux.

TightVNC 4 est-il concerné ?

Aucun avis ne couvre la ligne 4.x. Elle est sortie le 25 octobre 2026, après les correctifs 2.8.89 et 2.8.90. L'annonce 4.0 décrit un nouveau modèle de sécurité, pas ce bug du viewer. Confirmez auprès de l'éditeur si vous exécutez 4.x ; sur 2.8.x, passez en 2.8.90 quoi qu'il en soit.

Pourquoi n'y a-t-il pas de CVE ?

L'éditeur ne publie pas d'avis, et le rapport du chercheur est resté sans réponse, donc aucun CVE n'a été attribué au 2 novembre 2026. Les analyseurs de dépendances et de vulnérabilités ne peuvent donc pas signaler la plage concernée ; la vérification de version de « Suis-je concerné ? » est la seule détection fiable.

Où obtenir le viewer corrigé ?

Sur la page de téléchargement de l'éditeur, qui propose les installateurs 2.8.90 aux côtés de la ligne 4.0.2. Le code source 2.8.90 est publié sous GPL au même endroit, et c'est de là que vient l'analyse du correctif de cet article.

Repérez les hôtes exposant un viewer TightVNC en écoute avec Ostorlab

La découverte de surface d'attaque d'Ostorlab inventorie vos hôtes exposés sur internet, pour repérer quelles machines d'assistance répondent sur TCP 5500 avec un viewer en écoute et les mettre à jour en premier.

Références

  • SSD Secure Disclosure, « TightVNC Viewer Pre-auth RCE », l'analyse et l'exploit, crédit SeongJoon Cho de SSD Labs Korea : https://ssd-disclosure.com/tightvnc-viewer-pre-auth-rce/ (publiée le 29 octobre 2026 ; consultée le 2 novembre 2026)
  • Notes de version TightVNC, correctifs du Viewer en 2.8.89 et 2.8.90 : https://www.tightvnc.com/whatsnew.php (consultées le 2 novembre 2026)
  • Actualités TightVNC, annonces des 2 et 5 octobre et version 2.8.88 du 19 juin : https://www.tightvnc.com/news.php (consultées le 2 novembre 2026)
  • Page de téléchargement TightVNC, installateurs 2.8.90 et 4.x et archives sources GPL : https://www.tightvnc.com/download/ (consultée le 2 novembre 2026)
  • Distribution source TightVNC 2.8.88, le FrameBuffer vulnérable : https://www.tightvnc.com/download/2.8.88/tightvnc-2.8.88-src-gpl.zip (consultée le 2 novembre 2026)
  • Distribution source TightVNC 2.8.90, ViewerBufferSize.h et les sites d'appel de validation : https://www.tightvnc.com/download/2.8.90/tightvnc-2.8.90-src-gpl.zip (consultée le 2 novembre 2026)
  • CyberSecurityNews, « TightVNC Pre-Auth RCE Vulnerability Lets Hackers Execute Code on Windows PCs, PoC Released » : https://cybersecuritynews.com/tightvnc-pre-auth-rce-vulnerability/ (publié le 2 novembre 2026 ; consulté le 2 novembre 2026)
  • Catalogue KEV de la CISA, vérifié pour les entrées TightVNC : https://www.cisa.gov/known-exploited-vulnerabilities-catalog (consulté le 2 novembre 2026)