Date : 07/05/2003
Auteur : Etherlord (DHS Moderator)
Produit : Windows 9.x
---------------------------------------------------------
Vulnérabilité architecturale du système opératif
Windows
---------------------------------------------------------
And remember - if it ain't broke, hit it again - [C.Paget]
1. Introduction
===========
Le document présent est principalement livré à titre informatif
quant à la sécurité liée au système opératif
Windows. Le système Windows présente une vulnérabilité
architecturale qui rend délicate la "sécurisation forte"
d'un serveur. Il faut être conscient de cette vulnérabilité.
Les administrateurs et les développeurs trouveront au chapitre 5 quelques
recommandations pour limiter l'exploitation de cette vulnérabilité.
La démonstration du présent document est limitée à
l'exploitation théorique (l'application utilisée pour la demonstration
n'est PAS exploitable par ce procedé pour augmenter ses privilèges
puisque elle est executée avec les crédit de l'utilisateur. L'exploitation
de cette vulnérabilité s'applique à tous les processus
de Windows
ayant les privilèges SYSTEME (il y en as plusieurs, je vous laisse les
trouver..), toutefois il faut être conscient que l'application de la théorie
ne nécessite que des connaissances de base de la programmation des APIs
Windows. Un exploit pour cette vulnérabilité peut être envoyé
sous forme de texte par e-mail ou récupéré sur une page
web pour être ensuite compilé en local par l'utilisateur en utilisant
les utilitaires Windows installés par défaut debug.exe,
peut également compiler). Donc même une acompte Invité présente
cette vulnérabilité.
2. Les messages systèmes Windows
=========================
Les applications qui tournent sur le système opératif Windows
sont entièrement contrôlées à travers un mécanisme
de message. Quand une touche est activée, un message est envoyé
à la fenêtre active de l'application qui spécifie qu'une
touche a été activée. Quand Windows décide de redessiner
une partie de l'écran, il envoie un message a
l'application. En réalité, tous les événements qui
prennent place dans le système et dont l'application peut avoir besoin
sont transmis avec ce mécanisme de message. Ces messages sont places
dans une mémoire tampon et sont exécutés par l'application
dans leur ordre d'arrivée.
C'est un mécanisme très fiable pour contrôler les applications. A priori. En effet, sur les architectures Windows, ce mécanisme est mal conçu. N'importe quelle application peut envoyer un message à n'importe quel fenêtre qui est présente sur le système, indépendamment du fait que l'application soit propriétaire ou nom de la fenêtre à laquelle elle adresse un message. Il n'y a aucun mécanisme pour authentifier la source d'un message. Un message provenant d'une source malicieuse n'est pas discernable d'un message provenant du noyau du système. C'est cette absence d'authentification qui peut être exploitée, prenant en considération que les messages peuvent êtres utilisés pour manipuler des fenêtres et donc les processus qui en sont propriétaires.
Au niveau de la sécurité, on obtient ici un moyen facile d'escalader les privilèges d'un acompte. Pour exploiter cette attaque, il est nécessaire a priori de disposer d'un accès physique à la machine (en réalité, l'exploitation a distance est possible, elle nécessite une étape supplémentaire qui est l'exploitation d'un service réseau), toutefois cette attaque permet d'obtenir des privilèges administrateur depuis n'importe quel compte, y compris un compte invité.
3. Les dépassement de mémoire tampon (buffers overflow)
========================================
Les dépassements de tampon apparaissent lorsqu'un programme essaye de
stocker plus de données dans un tampon (zone temporaire de stockage de
données en mémoire) que ce dernier n'est capable de prendre en
charge. Les tampons sont à l'origine crées pour contenir un nombre
de données définies, l'information supplémentaire (qui
doit aller quelque part) peut écraser les tampons adjacents, modifiant
les données valides contenues dans le tampon adjacent. Lorsqu'un de ces
tampons fait partie de la pile d'exécution (stack), il est possible de
modifier le flux du programme et de lui faire exécuter du code arbitraire.
Le code sera alors exécuté avec les privilèges de l'application
exploitée, et non ceux de l'utilisateur.
Les dépassements de tampons sont à l'origine de nombreuses exploitations.
A l'origine, une exploitation utilisant les dépassements de mémoire
tampon nécessite une application "buggé" (Soit en utilisant
des fonctions qui présentent ce problème (en C: strcat(), strcpy(),
sprintf(), vsprintf(), bcopy(), gets(), et scanf()), soit en introduisant des
erreurs dans le code). Avec le système de messages Windows, même
une application protégée contre les dépassement de mémoire
tampon peut être exploitée, puisqu'il est possible de supprimer
la protection mise en place par le programme
si cette protection repose sur les mécanismes Windows (protection par
un paramétrage de l'objet).
4. Exemple de modification d'un executable livré avec le système.
=============================================
Ici sera seulement démontrée la partie qui vise à modifier un exécutable à priori fiable, pour le rendre vulnérable à une exploitation par dépassement de mémoire tampon. A l'origine, l'exécutable est protégé contre ce type d'attaque (champs d'entrée de la donnée limité en taille). Des démonstration plus complètes sont disponibles sur internet (exploitation de la console anti-virus McAfee).
Ce dont il faut bien prendre conscience, c'est que la majorité des entreprises qui travaillent avec des systèmes Windows ont toutes un environnement commun, et probablement des stratégies communes. On peut parier que la plupart des industries disposent de protection Anti-virus. Il y as de grande chances pour que ces anti-virus soient très répandus (Norton, McAfee, Trend). On peut également imaginer que la suite Office est présente dans de nombreuses industries. Il est donc très facile a quiconque dispose de bases en programmation d'installer ces logiciels chez lui et de tranquillement établir les programmes nécessaires à l'exploitation de ces produits très répandus. La phase d'attaque consisterait alors qu'au déploiement sur la machine cible d'un exécutable. N'importe quel utilisateur 'légal' d'un réseau est apte à mener à bien ce type d'attaque puisque qu'un compte 'invité' (guest) suffit à l'exécution de l'exploit.
L'exploitation du système de messages Windows peut être étendue a toutes les applications Windows.
4.1.Calc.exe
------------
Le but principal de cette attaque est de modifier les propriétés
d'un champs de manière à le rendre vulnérable à
l'exploitation d'un dépassement de tampon (buffer overflow). Les différentes
étapes de l'attaque consistent à :
- Identifier une sous-fenêtre de l'application (par exemple, une boite
d'édition) et obtenir son "handle" (identifiant Windows). -
Supprimer les restrictions liées à la longueur du message qui
peut être entré dans la boîte d'édition.
- Coller un morceau de code exécutable dans la boîte d'édition
précédemment modifiée.
- Forcer l'application à exécuter le code soumis.
Pour l'exemple, nous n'effectuerons que les deux premières étapes avec programme calc.exe (installé par défaut sur tous les OS Windows). La troisième étape est assez simple au niveau programmation (API SetDlgItemTextA), quand à la 4ème, il ne s'agit que de modifier l'adresse de retour d'un 'shellcode' par rapport à l'application exploitée. Ce dernier point n'étant pas le but de ce document, il sera laissé de coté.
1ère étape:
-----------
La première étape consiste à localiser un contrôle
d'édition ou de même type, un contrôle dans lequel on puisse
injecter des informations. Les restriction éventuelles sur ce contrôle
peuvent être désactivée. Il nous faut ici un logiciel qui
soit capable de lister pour un processus particulier les propriétés
de cette application (nom de classe, identifiant Windows, etc.). Pour notre
exemple, l'utilitaire Spy & Capure Version 2.70 a été utilisé.
Ce
logiciel liste les processus tournant en mémoire, et la sélection
d'un processus permet d'obtenir les informations recherchées:
Informations nécessaires à l'exploitation :
Nom de fenêtre : Calculatrice
Nom de classe : SciCalc
2ème étape:
-----------
Pour la deuxième étape, il s'agit d'adresser la boîte d'édition
de la calculatrice. Par défaut, cette boîte d'édition n'autorise
que l'insertion de 32 caractères.
La boîte d'édition étant considérée par le
système comme une sous-fenêtre de l'application calculatrice, nous
pouvons trouver son identifiant en recherchant d'abord l'identifiant de l'application
"calculatrice" à l'aide des informations trouvées précédemment
:
;---------------------------------------------------------
; Extrait de code assembleur windows 32 bit pour trouver
; l'identifiant de l'application avec FindWindow
.data
lp2ClassName db "SciCalc",0
lp2WindowName db "Calculatrice",0
.code
invoke FindWindow, addr lp2ClassName, addr lp2WindowName
.if eax!=NULL
mov hwndParent,eax ; on enregistre l'identifiant
;---------------------------------------------------------
Une fois l'identifiant de l'application trouvé, on peut rechercher l'identifiant
des sous-fenêtres en utilisant l'API FindWindowEx. L'identifiant de la
sous-fenêtre va nous permettre d'adresser des messages à cet objet.
Avec cet identifiant, on envoie d'abord un message pour supprimer la limite
du texte, puis on injecte le code a exécuter dans la boîte d'édition,
un appel a WM_TIMER lance l'exécution du code:
;---------------------------------------------------------
invoke FindWindowEx,hwndParent,hwndChildAfter, addr Ed1ClassName
, NULL
; si eax <>0, on as trouve l'identifiant
.if eax!=NULL
mov hwindfirst,eax
; on utilise les messages windows pour supprimer la limitte
invoke SendMessage,hwindfirst,EM_SETLIMITTEXT,ExtSize,NULL
; on injecte le shellcode
invoke SendMessage,hwindfirst,WM_SETTEXT,NULL,addr ShellCode
; on execute le shellcode avec WM_TIMER
invoke SendMessage,hwndParent,WM_TIMER,1,hwindfirst
;---------------------------------------------------------
Après exécution de l'exploit, la limite est supprimée.
5. Les Solutions Possibles :
===================
Il n'y a pas de réelle solution pour ce problème. La vulnérabilité
étant liée à l'architecture Windows, pour résoudre
le problème il faudrait que le système puisse :
- Interdire la transmission de messages entre des applications disposant de privilèges différents. (Un processus 'invité' ne devrait pas pouvoir envoyer un message de commande à un processus 'local system')
- Ajouter une information dans le message sur la source, et laisser l'application décider si elle doit ou ne doit pas prendre en compte le message.
Malheureusement, les fonctions nécessaires pour exécuter cela
sont absente du système d'exploitation Windows. Pratiquement, il n'y
a pas de solution simple possible. Microsoft est conscient du problème
depuis des années, il y a eus plusieurs tentatives pour modifier ce comportement
mais toutes les tentatives ont finalement apporté plus
de problèmes qu'elles n'en résolvent.
Les administrateurs et développeurs trouveront quelques conseils ci-après pour limiter l'exploitation de cette vulnérabilité. Ce ne sont que des conseils. Le système Windows présentant énormément de situation critiques, la sécurisation à 100% du coté application ne seras probablement jamais possible.
Administration des serveurs :
-----------------------------
- S'assurer qu'un serveur sensible soit physiquement inatteignable par les personnes
qui n'ont pas à accéder à ce serveur (ne JAMAIS négliger
la sécurité physique pour un serveur)
- Supprimer du serveur toutes les application installées par défaut qui ne sont pas nécessaire (supprimer physiquement les exécutables, les plus dangereux étant : debug.exe, cmd.exe, telnet.exe, mplay.exe) qui permettent l'exploitation ou peuvent êtres exploités. Certaines de ces applications devraient impérativement êtres supprimées).
- Ne pas exécuter d'application avec des privilèges supérieurs à ceux nécessaires au bon déroulement de l'application (ne pas installer un agent avec des privilèges LOCAL_SYSTEM si des privilèges BACKUP_OPERATOR sont suffisant).
Développement :
---------------
- Lors de la validation d'une donnée entrée par un utilisateur,
ne JAMAIS se fier à une limitation définie par le système
sur un objet (par exemple, longueur maximale d'un champs edit). TOUJOURS "sanitiser"
une donnée utilisateur par un traitement interne au programme.
- Vérifier en "live" que les paramètres des objets modifiables par messages n'ait pas étés modifiés après le lancement du programme dans le cas d'un élément critique (Interaction avec l'utilisateur ET le système).
Historique de la vulnérabilité:
-------------------------------
08/05/02 - Présentation de la vulnérabilité par Symeon
Xenitellis à la conférence IFIP/SEC2002
07/07/02 - S.Xenitellis rend la vulnérabilité publique a travers
plusieurs listes dédiées à la sécurité.
08/07/02 - Présentation de la vulnérabilité par S.Xenitellis
à la conférence ECIW
01/08/02 - Report de la vulnérabilité et présentation de
l'exploit "shatter attack" par Chris Paget (NGSS Software) à
Microsoft.
05/08/02 - Microsoft minimise le problème, et considère que cela
n'est pas lié à la sécurité car l'exploitation implique
soit que l'utilisateur exécute du code malicieux sur sa machine soit
que l'attaquant ait accès physique à la machine. (C'est oublier
le principale problème: escalade de privilèges)
05/09/02 - Microsoft reconnaît le problème dans une réponse
publique en signalant qu'il sont au courant du problème depuis 1994 (article
publié dans le Knowledge Base Microsoft)
11/12/02 - Première publication par Microsoft d'un patch censé
adresse une partie du problème (MS02-071 : Exploitation du message WM_TIMER).
17/12/02 - Microsoft met à jour les informations du bulletin MS02-071.
03/02/03 - Le patch est retiré, car il cause des problèmes sur
le système Windows NT
07/02/03 - Un nouveau patch est publié, le bulletin MS02-071 est mis
à jour. Le patch n'adresse toujours que WM_TIMER (symptôme), en
laissant de coté toutes les autres vulnérabilités liées
(cause du problème). Microsoft signale que les "good coding practices"
impliquent que les services qui interagissent avec le bureau ne doivent pas
tourner avec des privilèges élevés. Le point délicat
ici, c'est qu'une installation par défaut de Windows installe beaucoup
de services qui interagissent avec le bureau et disposent des privilèges
LOCAL_SYSTEM (un des privilège les plus élevé qu'il soit
possible d'obtenir sous Windows).
Références:
-----------
- Messages and Event-Driven Programming
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnw98bk/html/messageseventdrivenprogramming.asp
- Microsoft Security Bulletin MS02-071
Flaw in Windows WM_TIMER Message Handling Could Enable Privilege Elevation (328310)
http://www.microsoft.com/technet/treeview/?url=/technet/security/bulletin/MS02-071.asp
- A New Avenue of Attack: : Event-driven system vulnerabilities
http://www.isg.rhul.ac.uk/~simos/event_demo/
- Windows Still Image Privilege Elevation (A090700-1) - @stake Inc Security
Advisory
http://www.atstake.com/research/advisories/2000/a090700-1.txt
- Shatter Attacks - How to break Windows
http://security.tombom.co.uk/shatter.html
...::: Shatter Attacks By Etherlord:::...