Hardening consulting

Support d'UDP dans FreeRDP partie 1

Celà fait quelques temps que je n'avais rien posté. Pour commencer, je vous souhaite une bonne année 2021, plein de belles choses, des projets et puis la santé évidement ! Espérons que la Covid nous laissera un peu tranquille cette année.

Comme je travaille sur le support du transport UDP dans FreeRDP, je fais une petite série de posts sur ce sujet. On va commencer par un aperçu rapide de comment ça marche et ce que ça implique, et je rentrerais sans doute plus dans les détails dans des post suivants.


Aperçu du transport UDP

Documentation et spécifications

Le support UDP dans RDP est détaillé dans plusieurs fichiers de spécifications:

  • MS-RDPBCGR : la spécification de base du RDP, on a quelques flags dans les paquets GCC, et la mise en place du multi-transport;
  • MS-RDPEMT : la spécification du multi-transport, qui permet d'annoncer et de mettre en place plusieurs transports à la fois;
  • MS-RDPEUDP : la spécification du transport UDP lui-même;
  • MS-RDPEUDP2 : la nouvelle mouture du protocole UDP;
  • MS_RDPEDYC : la spécification des channels dynamiques;

Schéma général

Le multi-transport permet de transporter des données des channels sur de l'UDP, un des apports est la possibilité de faire un canal non fiable, permettant la perte de paquets. Néanmoins, il semble que cette capacité n'ai pas rencontré son public car la spécification MS-RDPEUDP2 ne propose plus qu'une version fiable

L'établissement du transport UDP se fait suivant cet enchaînement:

  • le client RDP se connecte en TCP, et commence la négociation;
  • il négocie du multi-transport sur la connexion TCP;
  • à l'iniative du serveur un ou plusieurs transports UDP sont établis;
  • les channels sont ensuite transférés sur les transports UDP;

Regardons un peu dans les détails.

Annonce de flags

Dans le premier paquet de négociation, il est de bon ton que le client annonce un correlationId, de cette manière le serveur pourra raccrocher une connexion UDP entrante à sa connexion TCP correspondante. L'association stricte entre la connexion UDP et son équivalente TCP est faite d'une autre manière, le correlationId permet juste des logs plus jolis avant que le transport UDP ne soit complêtement établi.

Ensuite, le client et le serveur doivent supporter le multi-transport en l'annonçant dans les paquets TS_UD_CS_MULTITRANSPORT et TS_UD_SC_MULTITRANSPORT.

Négociation multi-transport

Plus loin dans la phase de négociation, juste après la phase de licensing, on attaque la négociation du multi-transport elle-même. Les étapes de négociation sont les suivantes:

On a la Initiate Multitransport Request reçue par le client sur la connexion TCP. Puis le transport RDP-UDP est négocié, permettant d'échanger des paquets au dessus de l'UDP. Une fois cette couche basse établie, elle va être sécurisée en utilisant soit du TLS si la connexion est sans perte, soit du DTLS si c'est la version qui accepte la perte de paquets. Une fois le handshake SSL (ou DTLS) passé, du point de vue client, le transport est établi.

Au dessus de cette connexion en UDP, l'envoie d'un Tunnel Create Request par le client va permettre au serveur d'associer la connexion UDP créée avec la connexion originale en TCP. Le client peut ensuite envoyer la Initiate Multitransport Response sur la connexion TCP pour confirmer au serveur que le transport UDP est fonctionnel coté client et que la migration des channels sur le transport UDP peut commencer.

Conclusion

La suite dans les prochains épisodes...