remote desktop protocol
Security Operations

Remote Desktop Protocol : Exécution de la requête RDP externe

À la recherche de connexions RDP qui ont réussi à pénétrer au sein de votre réseau depuis l'extérieur ? Un guide étape par étape (et une requête pour vous aider à bien démarrer).

La fonction de la requête ‘RDP Logins from External IPs.sql’ est assez explicite, en parcourant son nom. Dans cet article, nous l’utiliserons pour rechercher des connexions RDP (Remote Desktop Protocol) réussies et établies à partir d’adresses IP externes, c’est-à-dire tout ce qui n’est pas conforme à la RFC 1918. Dans le cadre de cette démonstration, nous allons créer et exécuter la requête à proprement parler via notre service Sophos Central, mais les principes de base restent valables quel que soit l’outil d’investigation. Comme alternative, la vidéo intitulée “Executing the External RDP Query” ci-dessous vous montre plutôt les principales étapes importantes, plutôt qu’une description détaillée comme nous le faisons ici.

Construire et exécuter la requête

La première étape consiste à créer la requête, ce que vous ferez via Sophos Central dans :

Centre d’analyse des menaces> Live Discover> Mode concepteur

en cliquant sur le bouton ‘Créer une nouvelle requête’, comme illustré dans la figure 1.

remote desktop protocol

Figure 1 : Accès au bouton de création de requête

En cliquant sur le bouton, vous accédez à un écran avec une boîte SQL, dans laquelle vous collerez la requête suivante (également disponible sur notre Github) :

SELECT 

strftime('%Y-%m-%dT%H:%M:%SZ',datetime) AS date_time, 

eventid, 

CASE eventid 

   WHEN 21 THEN eventid || ' - Session logon succeeded' 

   WHEN 22 THEN eventid || ' - Shell start notification received' 

   WHEN 25 THEN eventid || ' - Session reconnection successful' 

   ELSE NULL 

END AS description, 

JSON_EXTRACT(data, '$.UserData.User') AS username, 

SUBSTR(JSON_EXTRACT(data, '$.UserData.User'), 1, INSTR(JSON_EXTRACT(data, '$.UserData.User'), '\') - 1) AS domain, 

JSON_EXTRACT(data, '$.UserData.Address') AS source_IP, 

JSON_EXTRACT(data, '$.UserData.SessionID') AS session_ID, 

CASE 

    WHEN JSON_EXTRACT(data, '$.UserData.Address') GLOB '*[a-zA-Z]*' THEN 'private_IP' 

    WHEN INSTR(JSON_EXTRACT(data, '$.UserData.Address'), '192.168.') = 1 THEN 'private_IP'   

    WHEN INSTR(JSON_EXTRACT(data, '$.UserData.Address'), '172.') = 1 AND CAST(SUBSTR(JSON_EXTRACT(data, '$.UserData.Address'), 5, 2) AS INTEGER) BETWEEN 16 AND 31 THEN 'private_IP' 

    WHEN INSTR(JSON_EXTRACT(data, '$.UserData.Address'), '10.') = 1 THEN 'private_IP' 

    WHEN INSTR(JSON_EXTRACT(data, '$.UserData.Address'), '127.') = 1 THEN 'private_IP' 

    WHEN JSON_EXTRACT(data, '$.UserData.Address') = '0.0.0.0' THEN 'private_IP' 

    WHEN JSON_EXTRACT(data, '$.UserData.Address') LIKE '%::%' THEN 'unknown' 

    WHEN JSON_EXTRACT(data, '$.UserData.Address') = '' THEN 'private_IP' 

   ELSE 'external_IP' 

END AS status, 

'TS LocalSession EVTX' AS data_source, 

'Logins.01.4' AS query 

FROM sophos_windows_events 

WHERE source = 'Microsoft-Windows-TerminalServices-LocalSessionManager/Operational' 

    AND eventid IN (21,22,25) 

    AND (status = 'external_IP' OR status = 'unknown') 

  

UNION ALL 

  

SELECT 

strftime('%Y-%m-%dT%H:%M:%SZ',datetime) AS date_time, 

eventid, 

CASE eventid 

   WHEN 1149 THEN eventid || ' - User authentication succeeded' 

   ELSE NULL 

END AS description, 

JSON_EXTRACT(data, '$.UserData.Param1') AS username, 

JSON_EXTRACT(data, '$.UserData.Param2') AS domain, 

JSON_EXTRACT(data, '$.UserData.Param3') AS source_IP, 

NULL AS Session_ID, 

CASE 

    WHEN INSTR(JSON_EXTRACT(data, '$.UserData.Param3'), '192.168.') = 1 THEN 'private_IP' 

    WHEN INSTR(JSON_EXTRACT(data, '$.UserData.Param3'), '172.') = 1 AND CAST(SUBSTR(JSON_EXTRACT(data, '$.UserData.Param3'), 5, 2) AS INTEGER) BETWEEN 16 AND 31 THEN 'private_IP' 

    WHEN INSTR(JSON_EXTRACT(data, '$.UserData.Param3'), '10.') = 1 THEN 'private_IP' 

    WHEN INSTR(JSON_EXTRACT(data, '$.UserData.Param3'), '127.') = 1 THEN 'private_IP' 

    WHEN JSON_EXTRACT(data, '$.UserData.Param3') = '0.0.0.0' THEN 'private_IP' 

    WHEN JSON_EXTRACT(data, '$.UserData.Param3') LIKE '%::%' THEN 'unknown' 

    WHEN JSON_EXTRACT(data, '$.UserData.Param3') = '' THEN 'private_IP' 

    ELSE 'external_IP' 

END AS status, 

'TS RemoteConnection EVTX' AS data_source, 

'Logins.01.4' AS query 

FROM sophos_windows_events 

WHERE source = 'Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational' 

    AND eventid = 1149 

    AND (status = 'external_IP' OR status = 'unknown') 

Une fois cette requête collée, vous sélectionnerez les machines sur lesquelles cette dernière doit être exécutée. La requête est spécifique à Windows ; l’exécuter sur des machines macOS ou Linux ne renverra aucun résultat, donc les désélectionner (dans l’option ‘Filtres -> Système d’exploitation’) est une bonne première étape. Au-delà de ce paramétrage, les besoins de chaque entreprise sont évidemment uniques. Cependant, il existe de solides arguments en faveur de l’exécution de la requête sur chaque machine Windows de votre réseau, même au niveau des systèmes endpoint, au cas où l’une d’elles serait exposée de manière incorrecte à Internet (malheureusement, nos investigateurs chargés de la réponse aux incidents découvrent ce type de cas bien plus souvent que vous ne pensez).

Cliquez sur ‘Mettre à jour les appareils sélectionnés’ pour confirmer vos choix, puis sélectionnez ‘Exécuter la requête’ en bas à droite pour la lancer (le système vous demandera de confirmer que vous souhaitez exécuter cette requête non testée ; validez et continuez). L’exécution de la requête commence ; la vitesse à laquelle les résultats sont renvoyés dépend du nombre d’appareils interrogés et de leurs connexions réseau. Une fois terminé, la colonne ‘Statut’ vous alertera sur la fin de la requête (ou, en cas de problème, de l’échec de cette dernière). Faites défiler vers le haut ; il y a une section intitulée ‘Résultats de la requête’ qui affiche les résultats. S’il n’y a rien, félicitations ! Aucune connexion RDP à partir d’adresses IP externes n’a été trouvée. Si toutefois des résultats devaient s’afficher…

Comprendre les résultats

Si votre requête renvoie des résultats, le premier champ à prendre en compte est le nom du système endpoint. Dans l’exemple ci-dessous (tiré du banc de test que nous avons mis en place pour réaliser notre vidéo), deux machines ont signalé qu’elles disposaient de connexions RDP externes.

remote desktop protocol

Figure 2 : Notre banc de test comportait deux machines, et ces deux machines ont été touchées par un RDP externe

Le développement des résultats affiche la date et l’heure auxquelles la connexion a eu lieu, l’ID d’événement renvoyé par la requête (avec une brève description de la signification de cet ID d’événement), le nom d’utilisateur du compte qui s’est connecté et l’adresse IP source à partir de laquelle ils se sont connectés. Les adresses non RFC 1918 prouvent que ces connexions ne proviennent pas de l’espace d’adressage privé du réseau.

Il convient de noter que, comme pour toute requête de ce type, des investigations plus approfondies sont nécessaires afin d’exclure les faux positifs. Cependant, un “faux” positif, à savoir une connexion externe particulière qui n’était en réalité qu’un simple administrateur ouvrant temporairement le RDP sur un serveur, mérite toujours d’être mieux compris. Comme nous l’avons noté plus tôt dans cette série d’articles, les attaquants sont incroyablement rapides à accéder à une connexion RDP ouverte. Si l’administrateur a réussi à se connecter, il y a de fortes chances qu’un attaquant ait également eu le temps de trouver le port ouvert. Une grande prudence suggérerait d’isoler l’appareil et de l’examiner plus en profondeur pour déceler toute compromission potentielle.

Remote Desktop Protocol : Présentation de la série d’articles

Partie 1 : Remote Desktop Protocol : Introduction (article, vidéo)
Partie 2 : Remote Desktop Protocol : Un RDP accessible depuis Internet (est dangereux) (article, vidéo)
Partie 3 : Remote Desktop Protocol : Requêtes pour investigation (article, vidéo)
Partie 4 : RDP et écart de fuseau horaire/Time Zone Bias (article, vidéo)
Partie 5 : Exécution de la requête RDP externe ([article en cours de lecture], vidéo)
Partie 6 : Exécution de la requête Login 4624_4625 (article, vidéo)
Dépôt de requêtes sur GitHub : SophosRapidResponse/OSQuery
Dépôt de la transcription des vidéos : sophoslabs/video-transcripts
Playlist YouTube : Remote Desktop Protocol : Présentation de la série d’articles

Billet inspiré de Remote Desktop Protocol: Executing the External RDP Query, sur le Blog Sophos.