Archive for mai, 2007

SSTIC

Demain commence la grande messe annuelle du SSTIC. J’ai décidé de m’y rendre cette année pour la première fois, même si les conférences sur Windows ne sont pas majoritaires j’espère y apprendre quelques trucs sympas et puis surtout le but premier, rencontré plein de monde.

http://www.sstic.org/SSTIC07/info.do

En attendant si vous vous demandez ou sont passés les post maladouf, sachez qu’ils vont revenir et que le prochain va vous plaire. Si, par malchance, vous vous ennuyez comme un rat crevé vous pouvez toujours aller lire le dernier phrack et renouer avec le old school hacker sp1r1t :]

http://www.phrack.org/ 

5 comments mai 29th, 2007

Madchat Reloaded

J’ai pu récupérer un backup officiel du fameux repository de madchat.org, ce même site qui ma fait découvrir beaucoup de choses et qui a fermé il y a quelques mois. Trouvant cette disparation plus que triste, j’ai décidé de l’upload sur mon compte, vous pouvez désormais le retrouverez (et vous y perdre à nouveau) à cette url.

http://ivanlef0u.fr/repo/madchat

4 comments mai 19th, 2007

Uninformed Volume 7

Aujourd’hui parait un nouvel Uninformed, au programme 3 papers dont 2 de Skape :

Reducing the Effective Entropy of GS Cookie Nous montre comment est calculé le cookie GS visant un éviter le débordement de pile, puis à travers des analyses statistiques nous montre qu’il est possible pour un attaquant local de déterminer un cookie.

Memalyze: Dynamic Analysis of Memory Access Behavior in Software . Super document montrant des techniques permettant de connaître les accès mémoire d’un process. La première le Dynamic Binary Instrumentation (DBI) consiste à un injecter dans le processus un code qui va exécuter les instructions, une sorte de traceur qui va vérifier les accès mémoire, dispo sous Linux sous le nom de DynamoRIO . La seconde méthode repose sur l’utilisation du gestionnaire d’exception, notamment sur le fait qu’en modifiant le Owner des pages mémoire du process afin quelles soient considérées comme des kernel pages, une exception interviendra dès qu’un code y accédera. Skape à implémenter une méthode qui consiste à créer un second mapping contenant la version originale des pages, donc avec le flag Owner normal, tandis que le premier mapping des pages représente les pages lockées. Ansi lorsqu’intervient une exception, il suffit de rediriger le code sur le second mapping. Cela permet d’éviter la modification en permanence du flag Owner des pages et d’échapper à pas mal de problème sur les environnements multithreadés. Enfin, la dernière méthode consiste à utiliser le null segment descriptor, en positionnant les segment CS et ES à 0, on récupère une exception à chaque accès mémoire, l’exception handler restore les segments et activz le trap-flag du registre EFLAGS, un seule instruction est donc exécutée par la suite, on remet les segments 0 et l’exécution repart.

Mnemonic Password Formulas Propose diverses techniques mnémonique pour retenir un password.

Add comment mai 14th, 2007

HideFromDebugger

Une explosion ! Vite je cours me mettre à l’abri, je prends mon AK-47 et m’accroupit, respirant calmement j’attends que l’ennemi sorte de son trou, il fait chaud, une goutte de sueur dégouline le long de ma tempe, ma combinaison est un vrai fourneau, j’ai peur ! Il se montre enfin ! Enculé de batard, tu vas la prendre ta rafale, TAC TAC TAC ! Headshot, Terrorists Wins. Ouf quelle partie, ca fait du bien de buter du noob à CS, surtout après une dure journée. Vous l’avez compris en ce moment je fous plus grand chose, petite période d’idle ou j’ai envie de me changer les idées et pour vous décevoir rien de tel qu’un post sans grand-intéret. Rien de bien extraordinaire, je vais juste vous parler d’un anti-debug peu connu.


En lisant de la doc sur l’API native, je suis tombé (entre 2 parties de CS) sur une feature NtSetInformationThread, appelé ThreadHideFromDebugger. L’utilisation est simple on appel NtSetInformationThread avec le ThreadInformationClass mit à ThreadHideFromDebugger (17) et un thread handle.

typedef enum _THREADINFOCLASS {

    ThreadHideFromDebugger=17

} THREADINFOCLASS;extern "C" ULONG __stdcall NtSetInformationThread(

    __in HANDLE ThreadHandle,

    __in THREADINFOCLASS ThreadInformationClass,

    __in_bcount(ThreadInformationLength) PVOID ThreadInformation,

    __in ULONG ThreadInformationLength

);

ULONG main()

{

 ULONG Status;

 Status=NtSetInformationThread(GetCurrentThread(), ThreadHideFromDebugger, NULL, 0);

 if(Status)

 	printf("Error with NtSetInformationThread : 0x%xn", Status);

__asm {int 3}

 return 0;

}

Après si on essaye de lancer le debugger sur ce thread, rien ne se passe, le breakpoint (int 3) n’est pas récupéré par le debugger. En fait toutes les exceptions ne sont plus passées au debugger :]

Pour comprendre il faut savoir que lorsque qu’on trace sous Olly, le debugger positionne le trap-flag du registre EFLAGS à 1, ainsi à chaque exécution d’instruction, le processeur va générer une exception, le débugger va la gérer et nous permettre de continuer sur la prochaine instruction et ainsi de suite. Si par malheur ces exceptions ne sont plus passées au debugger, il n’est plus possible de tracer le thread.

Ainsi dans le code plus haut, si vous lancer Olly sur l’exécutable vous ne verrez jamais le debugger vous signaler l’int 3, mais vous verrez la MessageBox « HideFromDebugger.exe a rencontré un problème et doit fermer. Nous vous prions de nous excuser pour le désagrément encouru. », du gestionnaire d’exception terminal, comme si le debugger n’avait pas été prit en compte. Dans un cas normal celui-ci break et nous propose de continuer l’exécution du programme.

Vu de haut c’est mignon comme feature, mais c’est toujours mieux de voir comment c’est fait dedans, aller hop wormhole trip avec IDA.

Voici le code qui correspond à la feature ThreadHideFromDebugger de NtSetInformationThread.

NtSetInformationThread

[...]

push    edi             ; HandleInformation

lea     eax, [ebp+pETHREAD]

push    eax             ; Object

push    dword ptr [ebp+AccessMode] ; AccessMode

push    _PsThreadType   ; ObjectType

push    20h             ; DesiredAccess

push    [ebp+Handle]    ; Handle

call    _ObReferenceObjectByHandle@24 ; ObReferenceObjectByHandle(x,x,x,x,x,x)

mov     esi, eax

test    esi, esi

jl      loc_49E718

mov     ecx, [ebp+pETHREAD]

lea     eax, [ecx+248h] ; eax=pETHREAD+0x248

lock or [eax], ebx ; ebx=4

jmp     loc_49E713

[...]

Le noyau récupère un pointeur sur la struture ETHREAD de notre thread avec l’api ObReferenceObjectByHandle puis accède au champ situé en 0×248 pour effectuer un « lock or [pETHREAD+0x248], 4. Le préfixe lock permet de verrouiller le bus de données afin que dans un environnement multiprocesseur d’autres threads ne modifient pas la variable en même temps.

En 0×248 de la structure ETHREAD on trouve :

kd>dt nt!_ETHREAD

[...]

   +0x248 CrossThreadFlags : Uint4B

   +0x248 Terminated       : Pos 0, 1 Bit

   +0x248 DeadThread       : Pos 1, 1 Bit

   +0x248 HideFromDebugger : Pos 2, 1 Bit

   +0x248 ActiveImpersonationInfo : Pos 3, 1 Bit

   +0x248 SystemThread     : Pos 4, 1 Bit

   +0x248 HardErrorsAreDisabled : Pos 5, 1 Bit

   +0x248 BreakOnTermination : Pos 6, 1 Bit

   +0x248 SkipCreationMsg  : Pos 7, 1 Bit

   +0x248 SkipTerminationMsg : Pos 8, 1 Bit

[...]

En faisant un OR avec cette variable, NtSetInformationThread positionne le bit HideFromDebugger à 1. Jusqu’ici rien d’extraordinaire.

Au moment de l’exception int 3, le processeur lance la routine le de l’IDT (Interruption Descriptors Table) appelé KiTrap03 qui va ensuite appelé les fonction suivantes :
KiTrap03->CommonDispatchException->KiDispatchException->DbgkForwardException

Arrivé dans DbgkForwardException on voit :

 __stdcall DbgkForwardException(x, x, x)

[...]

PAGE:004AB2C4 64 A1 24 01 00 00           mov eax, large fs:124h ; Current ETHREAD

PAGE:004AB2CA F6 80 48 02 00 00 04        test byte ptr [eax+248h], 4 ;ETHREAD+248 & HideFromDebugger

PAGE:004AB2D1 0F 85 58 7C 09 00           jnz loc_542F2F ; si HideFromDebugger enabled on ne passe pas l'except au debugger

[...]

La fonction DbgkForwardException va vérifier si le champ HideFromDebugger du thread courant est à 1, si oui alors l’exception n’est pas passé au debugger. Dans une situation classique l’exception est transmise au debugger via DbgkpSendApiMessageLpc qui va notifier à l’api WaitForDebugEvent qu’une exception s’est déroulé.

Voilà, vous trouverez le code/binaire ici :
http://ivanlef0u.fr/repo/HideFromDebugger.rar

4 comments mai 13th, 2007

Segmentation Fault

Par manque d’inspiration le contenu de ce post racontera la manière dont je me suis prit une grosse baffe dans ma gueule en voulant jouer avec mon OS. Ma péripétie commence à cause d’une simple interrogation, le genre de choses qu’on se demande uniquement sous la douche le matin, après avoir absorbé sa dose vitale journalière de chocapics, des questions auxquelles seul un manuel Intel peut répondre mais qu’on à peur d’ouvrir tellement ce genre de ebooks fait de la peur. Le trip est simple, pourquoi un code userland ne peut-il lire à une adresse supérieur à 0x7FFFFFFF ? Ok vous allez me dire que c’est là qu’est chargé le kernel et ses copines, mais le vrai problème est de savoir par quel méchanisme magique le système nous balance une exception 0xC0000005 (STATUS_ACCESS_VIOLATION) dans la face.


Je ne pars pas complètement apwal, je sais que le passage de ring3 en ring0 se fait à travers l’instruction sysenter. De plus dans un précédent post (SYSENTER, stepping into da ring0) j’avais décrit son fonctionnement et notamment après avoir modifié le MSR_SYSENTER_EIP avec l’API NtSystemDebugControl j’ai pu exécuter du code qui avait accès à toute la mémoire. La clé est donc dans le fonctionnement de sysenter !

Après m’être rappelé que sysenter modifiait l’EIP mais aussi les segments CS et SS, je me suis dit que ceux-ci devaient avoir quelque chose d’intéressant à m’apprendre. Hop je prend un thread userland au hasard et je regarde ses segments.

userland segments

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000
0x1B=  11 0 11b

0x23= 100 0 11b

0x3B= 111 0 11b

En même temps je retrouve la structure décrivant un segment.

typedef struct _X86_SELECTOR

    {

    union

        {

        struct

            {

            WORD wValue;            // packed value

            WORD wReserved;

            };

        struct

            {

            unsigned RPL      :  2; // requested privilege level

            unsigned TI       :  1; // table indicator: 0=gdt, 1=ldt

            unsigned Index    : 13; // index into descriptor table

            unsigned Reserved : 16;

            };

        };

    }

    X86_SELECTOR, *PX86_SELECTOR, **PPX86_SELECTOR;

Un segment contient donc, son niveau de privilège requis, un bit désignant une table, soit la gdt ou la ldt et l’indice d’une structure X86_DESCRIPTOR dans cette table. Ici le RPL est bien à 3 (11b), le champ TI vaut 0, on est donc dans la GDT. Pour CS sont descriptor est à l’indice 3 alors que celui de SS est à l’indice 4.

Après je compare les segments avec ceux d’un thread tournant en kerneland.

kernelland segments

cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000
0x08=   1 0 00b

0x10=  10 0 00b

0x23= 100 0 11b

0x30= 110 0 00b

Sysenter a fait son boulot, les segments CS et SS sont différents ainsi que FS mais ca c’est la fonction KiSystemService qui le redéfinit. Cette fois ci le descriptor de CS est à l’indice 1 dans la GDT et celui de SS à l’indice 2.

Sachant que un descriptor ressemble à :

typedef struct _X86_DESCRIPTOR

    {

    union

        {

        struct

            {

            DWORD dValueLow;        // packed value

            DWORD dValueHigh;

            };

        struct

            {

            unsigned Limit1   : 16; // bits 15..00

            unsigned Base1    : 16; // bits 15..00

            unsigned Base2    :  8; // bits 23..16

            unsigned Type     :  4; // segment type

            unsigned S        :  1; // type (0=system, 1=code/data)

            unsigned DPL      :  2; // descriptor privilege level

            unsigned P        :  1; // segment present

            unsigned Limit2   :  4; // bits 19..16

            unsigned AVL      :  1; // available to programmer

            unsigned Reserved :  1;

            unsigned DB       :  1; // 0=16-bit, 1=32-bit

            unsigned G        :  1; // granularity (1=4KB)

            unsigned Base3    :  8; // bits 31..24

            };

        };

    }

    X86_DESCRIPTOR, *PX86_DESCRIPTOR, **PPX86_DESCRIPTOR;

Après avoir vu ca, j’ai pas vraiment eu envie de dumper la GDT à la main, j’ai trouvé une extension ProtMode pour windbg qui permet d’afficher le contenu d’un X86_DESCRIPTOR de manière plus jolie.

A noter que la GDT peut etre retrouvé soit avec l’instruction sgdt, soit dans le KPCR avec la commande !pcr du KD.

kd> !ProtMode.Descriptor GDT 1

------------------- Code Segment Descriptor --------------------

GDT base = 0x8003F000, Index = 0x01, Descriptor @ 0x8003f008

8003f008 ff ff 00 00 00 9b cf 00

Segment size is in 4KB pages, 32-bit default operand and data size

Segment is present, DPL = 0, Not system segment, Code segment

Segment is not conforming, Segment is readable, Segment is accessed

Target code segment base address = 0x00000000

Target code segment size = 0x000fffffkd> !ProtMode.Descriptor GDT 2

------------------- Code Segment Descriptor --------------------

GDT base = 0x8003F000, Index = 0x02, Descriptor @ 0x8003f010

8003f010 ff ff 00 00 00 93 cf 00

Segment size is in 4KB pages, 32-bit default operand and data size

Segment is present, DPL = 0, Not system segment, Data segment

Segment is not conforming, Segment is readable, Segment is accessed

Target code segment base address = 0x00000000

Target code segment size = 0x000fffff

------------------- Code Segment Descriptor --------------------

GDT base = 0x8003F000, Index = 0x03, Descriptor @ 0x8003f018

8003f018 ff ff 00 00 00 fb cf 00

Segment size is in 4KB pages, 32-bit default operand and data size

Segment is present, DPL = 3, Not system segment, Code segment

Segment is not conforming, Segment is readable, Segment is accessed

Target code segment base address = 0x00000000

Target code segment size = 0x000fffff

kd> !ProtMode.Descriptor GDT 4

------------------- Code Segment Descriptor --------------------

GDT base = 0x8003F000, Index = 0x04, Descriptor @ 0x8003f020

8003f020 ff ff 00 00 00 f3 cf 00

Segment size is in 4KB pages, 32-bit default operand and data size

Segment is present, DPL = 3, Not system segment, Data segment

Segment is not conforming, Segment is readable, Segment is accessed

Target code segment base address = 0x00000000

Target code segment size = 0x000fffff

Comme prévu le premier descriptor est de type Code segment et possède un DPL (Descriptor Privilege Level) à 0, notre segment CS en ring0.
Le second descriptor, segment SS ring0.
Le troisième, segment CS ring3
Le quatrième, segment SS ring3.

Ici les segments sont en Flat-model, c’est à dire qu’ils décrivent entièrement l’espace mémoire (segment size*4KB).

Par contre pour le segment FS, indice 7 dans la GDT pour le userland.

kd> !ProtMode.Descriptor GDT 7

------------------- Code Segment Descriptor --------------------

GDT base = 0x8003F000, Index = 0x07, Descriptor @ 0x8003f038

8003f038 ff 0f 00 e0 fd f3 40 7f

Segment size is in bytes, 32-bit default operand and data size

Segment is present, DPL = 3, Not system segment, Data segment

Segment is not conforming, Segment is readable, Segment is accessed

Target code segment base address = 0x7ffde000

Target code segment size = 0x00000fff

L’adresse de base est 0x7ffde000 qui correspond à l’adresse du TEB du thread courant, attention depuis xp sp2 cette adresse est randomisé pour chaque threads, mais c’est pas grave avec fs:[0] on la retrouve :p

Pour un thread ring0 le segment FS vaut :

kd> !ProtMode.Descriptor GDT 6

------------------- Code Segment Descriptor --------------------

GDT base = 0x8003F000, Index = 0x06, Descriptor @ 0x8003f030

8003f030 01 00 00 f0 df 93 c0 ff

Segment size is in 4KB pages, 32-bit default operand and data size

Segment is present, DPL = 0, Not system segment, Data segment

Segment is not conforming, Segment is readable, Segment is accessed

Target code segment base address = 0xffdff000

Target code segment size = 0x00000001

En fs:[0] on retrouve l’adresse de la structure KPCR, ca peut toujours servir, notamment dans un shellcode :]

Lorsque j’essayais de lire une adresse supérieure à 0x7FFFFFFF avec un thread ring3 je me mangeais une exception car j’essayais d’accéder à une kernel page alors que mon CPL (Current Privilege Level) était à 3. La MMU génère une interruption 14 (Page Fault) qui est gérée par la routine de l’IDT KiTrap0E puis par MmAccessFault.

Je me suis dit qu’il suffisait de modif les segments à la main, comme le fait sysenter, pour avoir un thread tournant en ring0 (Il est con le Ivan parfois quand même ….). Sous Olly c’est possible, alors je lance un programme, modif ses segments pour avoir le CS et SS pareil qu’un thread ring0, je relance le thread et là c’est le drame ! Je me mange une exception. Evidemment je m’y attentais quand même un peu, ca paraissait un peu trop facile :) Par contre il me fallait comprendre pourquoi l’exception avait été générée.

Arrivé à ca point, pas le choix, faut regarder les man Intel, pénible corvée qui doit se faire en portant une combinaison NBC et des chaussettes marsupilami. Après quelques recherches, j’apprends que depuis tout petit on me ment, les segments ne font pas que 16 bits !! Il existe tout une partie cachée qui contient notamment le DPL du segment ! En fait cela permet d’éviter au processeur des cycles en plus de lecture pour lire la GDT. Ce cache ne peut être modifié directement mais des instructions comme sysenter le mettent à jour, comme le montre le manuel de l’instruction :

CS.SEL  <- SYSENTER_CS_MSR (* Operating system provides CS *)

(* Set rest of CS to a fixed value *)

CS.BASE  <- 0; (* Flat segment *)

CS.LIMIT <-  FFFFFH; (* 4-GByte limit *)

CS.ARbyte.G <-  1; (* 4-KByte granularity *)

CS.ARbyte.S  <- 1;

CS.ARbyte.TYPE  <- 1011B; (* Execute   Read, Accessed *)

CS.ARbyte.D <-  1; (* 32-bit code segment*)

CS.ARbyte.DPL <-  0;

CS.SEL.RPL <-  0;

CS.ARbyte.P <-  1;

CPL <-  0;

Donc même après avoir modifié le segment selector, le système remarquant que le RPL du segment ne correspond pas au DPL contenu dans le cache nous balance une interruption dans la face. Ouinn ….

Bref j’ai prit une baffe mais j’ai compris pourquoi :]

Références :
http://www.awprofessional.com/articles/article.asp?p=167857&rl=1

http://www.codeguru.com/cpp/w-p/system/devicedriverdevelopment/article.php/c8223__1/

http://www.summitsoftconsulting.com/SampleCode/ProtMode.zip

http://www.internals.com/articles/protmode/protmode.htm

http://www.sandpile.org/ia32/sreg.htm

3 comments mai 5th, 2007


Calendar

mai 2007
L Ma Me J V S D
« avr   juin »
 123456
78910111213
14151617181920
21222324252627
28293031  

Posts by Month

Posts by Category