Tuesday, August 10, 2010

Et un 42e bug dans xxxCreateWindowEx

Celui merite le detour dans la mesure ou il etait connu depuis 2007:

http://social.msdn.microsoft.com/Forums/en-US/windowsgeneraldevelopmentissues/thread/57c3783b-dd38-4a57-9217-61a920541ad0

En retournant un pseudo handle HWND_TOPMOST dans le champ hwndInsertAfter d'un hook WH_CBT, on aboutit a une violation d'acces, exploitable si l'on mappe l'espace a NULL (difficilement, mais Ronald a fait quelque chose de plus ou moins stable).

Les personnes susceptibles de Googler "windows bluescreen" auront eu un local 0day pendant 3 ans 1/2. Malheureusement, Core Security l'a tue(r), et a ete credite a la place de "JonnyDeep" qui a fait l'effort de le reporter mais n'a pas ete ecoute par MS (ils devraient lire leurs propres forums de temps en temps!).

C'est dingue ce que l'on trouve sur le Windows Developer Center :)

Edit: Et aussi, contrairement a la precedente, la vulnerabilite n'est pas specifiee comme ayant ete connue du public. Duree de vie: 1301 jours (pour ceux qui veulent faire des slides sur les 0days).

Thursday, July 1, 2010

Monday, June 21, 2010

MS10-032, ou pourquoi c'est mal de changer de parent lors de la creation d'un enfant

Dans le bulletin MS10-032, trois vulnerabilites ont ete corrigees: CVE-2010-0485, CVE-2010-0484, CVE-2010-1255. Mais seule la premiere a un indice d'exploitabilite de 1. Il est interessant de constater que personne n'est credite pour la decouverte de cette vulnerabilite, decrite comme etant "Win32k Window Creation vulnerability". De plus, le bulletin specifie que la vulnerabilite a ete portee a la connaissance du public, mais il n'y a pas d'exploit circulant. Etrange.

Une rapide analyse differentielle du binaire (win32k.sys) mettra en evidence le rajout d'un "UnlinkWindow" dans une branche du code qui n'est atteinte que si WM_NCCREATE rate. Les fonctions "LinkWindow" et "UnlinkWindow" sont utilisees pour lier parents et enfants entre eux, pour la transmission de messages, le "Z-ordering", etc. Cependant, la liaison d'un enfant fraichement cree avec son parent n'a lieu qu'apres un WM_NCCREATE ayant reussi. Quel est donc l'interet de de-lier un enfant dont la creation a echoue, a un parent qu'il n'a pas? Tout simplement parceque dans le gestionnaire de WM_NCCREATE, il est possible de faire appel a SetParent() et donc de changer le parent d'un enfant en cours de creation.

Faire appel a SetParent() dans le gestionnaire de WM_NCCREATE et retourner 0, entrainera un cas singulier ou le parent pense qu'il a un enfant mais l'enfant a en fait ete detruit par un xxxFreeWindow(). Certains penseront de suite a un cas d'utilisation apres liberation, mais c'est en fait un chouillat plus complique. Le lien qui existe fait que lors de sa destruction, l'enfant est marque comme detruit mais pas libere. C'est moche, ca nous aurait facilite la tache. On se retrouve alors avec un enfant invisble, marque comme detruit, et qui ne repond a aucun message. Seule specificite de l'enfant, son parent est NULL. Il n'est pas facile de referencer le parent d'un enfant qui n'accepte aucun message. Il faut donc trouver un message a envoyer au parent, qui va etre diffuse a ses enfants, dont le traitement devra entrainer un referencement du parent. Il s'avere que deplacer le parent mettra en branle cette chaine d'evenements et se terminera en ecran bleu.

Quelques commentaires. Je pense que j'ai du rater quelque chose, parceque l'exploitation du chemin que j'ai trouve ne merite clairement pas un "1", c'est plus un 1.5 - 2. Certes on dipose de toutes les informations necessaires localement, mais la primitive que l'on obtient, une addition dans une boucle qui va finir par crasher, est difficilement exploitable. Je reviens maintenant sur le fait que cette vulnerabilite etait connue du public. Il faut remonter jusqu'en 2004 pour trouver une trace de ce bug:

http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.kernel/2004-03/0602.html

microsoft.public.win32.programmer.kernel n'etait probablement pas le bon endroit pour signaler une faille de securite. Neanmoins certaines personnes attentives auront pu beneficier d'une elevation de privileges dans TOUTES les versions de Windows pendant ces 6 dernieres annees...

Edit: Un lien envoye par ivanlef0u sur un doc de taviso sur les parents des fenetres: https://docs.google.com/View?id=dfqd62nk_228h28szgz. Interessant!

Tuesday, May 25, 2010

Question du Jour

Trouve dans une DLL d'un systeme d'exploitation bien connu:

lea eax, [ebp+var_44]
push eax ; hMem
call ds:__imp__LocalFree@4 ; LocalFree(x)

Quelqu'un peut-il me dire:
  1. Pourquoi c'est "mal"?
  2. Quelle est l'erreur du programmeur qui a mene a ce code?
  3. Comment exploiter cela?
Par une operation du Saint Esprit, le code n'est pas atteignable dans la DLL en question. C'est moche.

Wednesday, May 19, 2010

Exception Culturelle

La derniere fois que je suis tombe sur du code promouvant l'exception culturelle Francaise, il s'agissait de cles DES specifiees en dur dans le Protected Storage. Cette fois-ci, on va regarder SChannel.

Un utilisateur averti pourra se demander pourquoi dans SChannel v5.1.2600.5834 (XP SP3 US plus ou moins a jour) on trouve la fonction IsSchEncryptionPermitted(), qui contient:

call ds:__imp__GetSystemDefaultLCID@0 ; GetSystemDefaultLCID()
cmp ax, 40Ch
jz short loc_767F41A7
push 0Ah ; cchData
lea ecx, [ebp+LCData]
push ecx ; lpLCData
push 5 ; LCType
push eax ; Locale
call ds:__imp__GetLocaleInfoA@16 ; GetLocaleInfoA(x,x,x,x)
test eax, eax
jz short loc_767F41A7
lea eax, [ebp+LCData]
push eax
call _MyStrToL@4 ; MyStrToL(x)
cmp eax, 21h
jnz short loc_767F41B8
loc_767F41A7: ; CODE XREF: IsSchEncryptionPermitted()+1Aj
; IsSchEncryptionPermitted()+2Dj 
and _g_ProtEnabled, 0FFFFFFFCh
mov _g_fFranceLocale, 1

Sauf que cette fois ci, le resultat n'est pas le meme. Si le Windows est francophone, on enleve les deux bits de poids faible de _g_ProtEnabled et on met a 1 une variable obscure.

Dans le code de SslReadRegOptions(), si _g_fFranceLocale est non 0, on ne prend pas en compte l'activation ou desactivation des protocoles specifies dans la base de registre, decrit dans la KB187498, si les bits de poids faible sont presents.

Les bits utilises pour l'activation des protocoles sont:
  • "Multi-Protocol Unified Hello\\Client": 80000000h
  • "Multi-Protocol Unified Hello\\Server": 40000000h
  • "PCT 1.0\\Client": 2
  • "PCT 1.0\\Server": 1
  • "SSL 2.0\\Client": 8
  • "SSL 2.0\\Server": 4
  • "SSL 3.0\\Client": 20h
  • "SSL 3.0\\Server": 10h
  • "TLS 1.0\\Client": 80h
  • "TLS 1.0\\Server": 40h

En conclusion, si je ne me suis pas plante, pas de drame - a part qu'un Windows francophone ne puisse pas faire de PCT du tout (client ou serveur). Ca m'aurait ete utile de savoir ca en 2004 pour l'exploit PCT Handshake...

Si quelqu'un veut confirmer, amusez-vous, je testerai sans doute dans la semaine pour verifier et mettrai a jour le post. Je n'ai pas d'explication au bannissement de PCT en France.

Et joyeux anniversaire a ma soeur!

Exploiter un double free() sous Windows

Un soir, une discussion avec Ronald et Sean nous a mene sur le sujet des doubles free() sous Unix, et je me suis rendu compte que je n'avais jamais exploite un double free() sous Windows. Bien que la problematique ne soit pas extremement complexe, il semblerait qu'il n'y ait pas des masses de documentation sur le sujet, a part une entree de sh0ck qui se retrouve massacree un peu partout.

Bien entendu, de nombreux elements entrent en compte:
  • Y a-t-il ecriture des donnees entrent les deux free()?
  • Le Heap en question a-t-il un Lookaside?
  • Est-ce que le Lookaside a atteint sa profondeur maximale avant le 1er free()? Apres?
  • Le Chunk libere est-il VirtualAllloc()'ed?
Quelques inexactitudes sur le sujet:

Tout d'abord: le free() d'un chunk deja marque comme libere (Chunk.Flag & 1 == 0) n'a aucun effet. Donc contrairement a ce qu'affirment des papiers comme Towards Automatically Generating Double-Free Vulnerability Signatures Using Petri Nets (1), meme s'il y a possibilite d'ecriture dans la partie data du chunk entre les deux free(), il ne se passera rien. S'il y a liberation, ecriture puis allocation, c'est une histoire differente (unlink sur un LIST_ENTRY maitrise qui donne un Write4) et ce n'est pas un double free().

Ensuite, si le chunk est VirtualAlloc'ed() - c'est usuellement le cas si la taille/8 est > 0xfe00 qui est le seuil par defaut - le 1er free() va retourner la page au gestionnaire de memoire de Windows qui va decommit la zone rapidement. Cela entrainera une violation d'acces lors du second free().

Nous sommes donc restreints aux cas ou le chunk est libere vers la Lookaside puisque dans ce cas la le chunk est toujours marque comme occupe. Donc:
  1. Le Heap en question doit avoir un Lookaside
  2. Le free() doit etre sur un chunk dont la taille est < 1024
  3. L'entree correspondante du Lookaside doit avoir au moins 1 place disponible (la profondeur par defaut est 4 la plupart du temps) sinon il sera libere vers la FreeList[]
Apres, il existe plusieurs possibilites, que l'on trouvera decrites dans une entree du blog de Symantec par Matt Connover.
  • Premier free() vers le Lookaside qui se retrouve plein entrainera un second free dans la FreeList[] (et potentiel coallesce) avec ecrasement du LIST_ENTRY apres premiere allocation, et une entree de Lookaside pointant vers le chunk libre (de la FreeList[]) suivant.
  • Premier et second free() vers le Lookaside, qui entrainera une primitive WriteN lors de la troisieme allocation d'un chunk de la taille en question.

Au final, un double free() ca s'exploite relativement bien dans XP et 2003, mais pas comme le decrivent certains.

Edit: petite correction dans le 1er cas.

(1): "After it has been freed, the programmer mistakenly uses temp and writes X in the first 4 bytes and Y in the second 4 bytes of temp. Then the programmer frees temp again. The system will then try to insert temp into the free list for a second time right before where it is already inserted."

Thursday, May 6, 2010

Supernaturel

Ce soir, Sam & Dean rencontrent le 3e Cavalier de l'Apocalypse: Mort. Cela faisait un moment que je n'avais pas autant accroche a une serie TV - mais Supernatural semble combler le manque. Voici le trailer de l'episode en attendant la diffusion dans une heure!