vendredi 8 août 2008

How to pwn lilxam's toolz :).

Un titre un peu provacateur, mais rien de méchant, juste un petit jeu entre lilxam et moi ; autrement dit mon article n'est pas là pour dénigrer son travail ou autre bien au contraire.
Les avertissements étant fait, rentrons dans le vif du sujet .. :).

Il y a quelques temps, j'ai entamé l'écriture d'un petit post concernant une technique de DKOM aboutissant à caché un processus (plus ou moins bien justement).
Le noyau possède un chainage de structures de type EPROCESS (par une liste doublement chainé à l'offset 0x088), il était donc possible d'unlinker une structure en particulier.
Le processus se retrouvait alors protégé de l'énumération par le taskmgr.exe ou encore ProcessExplorer.
C'est à présent que lilxam entre en jeu.

Peu de temps après mon petit Proof of Concept, il met en place une technique userland permettant d'énumérer les processus malgré la modification des structures en mémoire.
Cet technique en question, très ingénieuse au passage, permettant de récupérer le nom des processus en bruteforçant les PIDs de ceux-ci.
Seulement, tout cela m'interpelle, comment était-il possible de retrouver ce processus, alors qu'il n'était plus présent dans les structures EPROCESS ..?

La réponse ne devrait pas être trop complexe à rechercher ; en effet un commentaire de Ivanlef0u nous donne de précieuses informations : il aborde la présence d'une mystérieuse table prénommé PspCidTable référençant des informations concernant les processus à savoir une translation entres PIDs/TIDs et objet EPROCESS/ETHREAD.

Nous voilà sur la bonne route, sortons IDA afin d'analyser les apis utilisées dans le code de lilxam ; le réel problème étant de savoir comment le système se débrouille pour trouver le processus en question, désassemblons un peu OpenProcess exporté par kernel32.dll.
Nous suivons en premier lieu les appels successif à savoir:

->OpenProcess
-->NtOpenProcess
--->ZwOpenProcess

Nous savons bien que le système afin de permettre l'appel d'un syscall va passer par la SSDT pour retrouver l'adresse de la fonction associé à son numéro de syscall (0x7a pour NtOpenProcess).
Balayons alors ce code à la recherche de la translation PID/TID en objet EPROCESS/ETHREAD :

PAGE:004A9C92 cmp [ebp+var_1A], 0
PAGE:004A9C96 jnz loc_52ADDF
PAGE:004A9C9C cmp [ebp+var_19], 0
PAGE:004A9CA0 jz loc_50F76D
PAGE:004A9CA6 mov [ebp+var_30], esi
PAGE:004A9CA9 cmp [ebp+var_28], esi
PAGE:004A9CAC jnz loc_4D88A0
PAGE:004A9CB2 lea eax, [ebp+var_24]
PAGE:004A9CB5 push eax
PAGE:004A9CB6 push [ebp+var_2C]
PAGE:004A9CB9 call _PsLookupProcessByProcessId@8

L'appel à PsLookupProcessByProcessId est plus que révélateur, son nom en dit assez large sur son rôle et de plus cette fonction est renseigné par la msdn.
Désassemblons cette dernière fonction, notre réponse y est surement caché :).


PAGE:004A9B25 mov edi, edi
PAGE:004A9B27 push ebp
PAGE:004A9B28 mov ebp, esp
PAGE:004A9B2A push ebx
PAGE:004A9B2B push esi
PAGE:004A9B2C mov eax, large fs:124h
PAGE:004A9B32 push [ebp+arg_0]
PAGE:004A9B35 mov esi, eax
PAGE:004A9B37 dec dword ptr [esi+0D4h]
PAGE:004A9B3D push _PspCidTable
PAGE:004A9B43 call _ExMapHandleToPointer@8
PAGE:004A9B48 mov ebx, eax
PAGE:004A9B4A test ebx, ebx


Mais que voyons nous ; notre"PspCidTable".
Arrivé ici nous comprenons alors que les apis qu'utilise notre très cher lilxam ; en particulier OpenProcess se base donc sur cette fameuse table pour retrouver notre processus à partir de son PID.
Sans plus attendre je vous recommande (encore) un article de mon noble jedi ; celui-ci traite de long en large les tables de type HANDLE_TABLE au prototype suivant :


lkd> dt nt!_HANDLE_TABLE
+0x000 TableCode : Uint4B
+0x004 QuotaProcess : Ptr32 _EPROCESS
+0x008 UniqueProcessId : Ptr32 Void
+0x00c HandleTableLock : [4] _EX_PUSH_LOCK
+0x01c HandleTableList : _LIST_ENTRY
+0x024 HandleContentionEvent : _EX_PUSH_LOCK
+0x028 DebugInfo : Ptr32 _HANDLE_TRACE_DEBUG_INFO
+0x02c ExtraInfoPages : Int4B
+0x030 FirstFree : Uint4B
+0x034 LastFree : Uint4B
+0x038 NextHandleNeedingPool : Uint4B
+0x03c HandleCount : Int4B
+0x040 Flags : Uint4B
+0x040 StrictFIFO : Pos 0, 1 Bit


Ce type de table est d'ailleurs presque omni-présent dans les processus ; les handles que gèrent un processus sont stockés dans une table de ce genre.
Celle-ci est accessible à l'offset 0x0c4 :


lkd> dt nt!_EPROCESS
[...]
+0x0c4 ObjectTable : Ptr32 _HANDLE_TABLE


A présent, parlons PspCidTable.
En glanant sur le net, on s'aperçoit assez rapidement qu'il y a quelques années la modification
de cet table était une technique à la pointe dirais-je.
Cependant, je me suis vite rendu compte que mes parents ont entrepris ma construction trop tard :p ; en effet mon implémentation ce chargeait d'enlever l'objet EPROCESS du processus à caché, mais malgrès cela RkUnhooker, anti-rootkit digne de ce nom, trouve toujours le moyen de retrouver l'objet EPROCESS, et donc de permettre le kill de celui-ci :/.
Un peu frustré, je commence à m'interroger sur la technique que RkUnhooker pourrait déployer afin de retrouver ce maudit processus.
En analysant la définition de la structure ETHREAD on peut remarquer qu'il existe un lien avec la structure EPROCESS associé, à l'offset 0x220:

lkd> dt nt!_ETHREAD
[...]
+0x220 ThreadsProcess : Ptr32 _EPROCESS


; on ne peut que se demander
si RkUnhooker ce focalise sur les threads, et remonte au processus par le biais de divers fonctions.
Me voilà repartit dans cette table, afin d'enlever les objets ETHREADs .. après l'implémentation, à ma grande surprise le processus devient inactif ; zombie...

C'est donc à ce moment là que les questions jaillissent à travers mon esprit :

- Comment RkUnhooker remet la main sur mon processus ?
- Quel(s) technique(s) utilise t-il pour cela ?
- Existe t-il un autre endroit où une liste des processus lancées sur le système est disponible ?

Voilà concernant la PspCidTable, ma fonction permet alors de supprimer l'entrée concernant le processus à caché dans la table ; l'outil de lilxam est donc finalement inefficace sur ce coup là .:p.



Comme je le racontais plus haut, cette implémentation est trop maigre pour permettre de leurrer RkUnhooker.
C'est donc ainsi que commence mes recherches sur les techniques existantes permettant la protection d'un processus de l'énumération. Après quelques recherches sur la toile, mon regard s'attarde sur cette technique ; en effet le processus vital csrss.exe contiendrait une liste des processus lancée sur le système.
L'auteur de la technique explique très bien les faits et son analyse est détaillée ; en quelques mots, le processus tiens à jour une liste des processus lancés sur le système sous forme de liste chainée.Il est alors aisé pour nous de pratiquer un unlink ..

Pour un projet personnel, j'ai décidé de porter cette unlink en ring0 ; celle-ci devient alors tout de suite bien plus intéréssante car on est obligé de faire appel à pleins de petites choses pour arrivé à nos fin : du parcours de PE, de l'attachement à l'user-space d'un processus et j'en passe.

Les liens :
-PspCidTable PoC
-UnlinkListEntryInCsrss

Sinan si vous ne savez pas quoi faire, je vous conseil d'aller faire un tour sur le site de la F.A.T.
Cette petite team aux membres bien sympathiques publient des codes et papers vraiment géniaux ( je pense au dernier que j'ai lu ; autrement dit le paper concernant win32.leon par kaze ) ..enfin bref à bookmarker pour ceux qui ne connaissent pas :).

Et si vous en voulez encore un peu, je vous conseil de lire les derniers articles de deux de mes amis :

-Celui de rAsM ; monsieur met en place une technique pouvant servir de base à un potentiel keylogger kernel (a condition de patcher les BSODs :))).

-Celui de Ivanlef0u ; mon s1ths préféré propose un petit article concernant le subsystem csrss en abordant notament les processus consoles.

Pour clore ce petit post, un dernier lien ; celui-ci vient tout droit des dragons asiatiques ..Sudami reverseur de talent continus de nous faire réver en nous proposant de nouvelles techniques de DKOMs ; celle-ci aborde le hook d'une fonction stockée dans la structure liée aux Objects Types Initializers ( ..qui m'avait mis en échec ici ).
Bien evidement, raffolant de ce genre de technique je m'empresse de mettre en place un petit driver capable de placer ce hook mais c'est (du moins chez moi (XP SP2 FR)) un échec.. la routine est apparement bien appelé par le system mais en aucun cas elle empèche la fermeture du processus.
Peut-être que sudami explique les limites de sa technique dans son article, ou que celle-ci est valable avec des pré-requis.. Enfin bon si quelqu'un en sait plus qu'il me contacte :).

Voilà pour ce petit article, en espérant que je vous aurrez appris quelque(s) chose(s),
bonne journée à vous.
PS : Bonne rentrée à ceux qui ne l'ont toujours pas faite.