Üb3rGh0stWr1t1nG

juin 27th, 2007 at 06:18 admin

Imaginez vous êtes sur une b0x mais il y a méchant HIDS (Host Intrusion Detection System) qui vous empêche d’ouvrir un handle sur un process et sur tout ses threads, en utilisant par exemple un hook SSDT sur les API NtOpenProcess et NtOpenThread. Nous, comme on est des méchants, on voudrait bypass cette mesure (évidemment on ne peut pas loader de driver). Dans ce post je propose une méthode permettant d’injecter du code dans un process, sans utiliser de NtOpen* sur celui-ci, je préviens quand même, il ne s’agit pas d’un hack, mais plutôt de jongleries avec les différentes API et particularités de Windows qui de plus requiert certains privilèges alors n’espérer rien de révolutionnaire. Mais d’abord regardons comment fonctionne les API NtOpenProcess et NtOpenThread :

NTSTATUS
NtOpenProcess (
    __out PHANDLE ProcessHandle,
    __in ACCESS_MASK DesiredAccess,
    __in POBJECT_ATTRIBUTES ObjectAttributes,
    __in_opt PCLIENT_ID ClientId
    );

NTSTATUS
NtOpenThread (
    __out PHANDLE ThreadHandle,
    __in ACCESS_MASK DesiredAccess,
    __in POBJECT_ATTRIBUTES ObjectAttributes,
    __in_opt PCLIENT_ID ClientId
    );

Les 2 API’s demandent en paramètre l’ID de l’objet que souhaite ouvrir, le champ ClientId étant un pointeur sur une structure CLIENT_ID qui est définit par :

typedef struct _CLIENT_ID {
    HANDLE UniqueProcess;
    HANDLE UniqueThread;
} CLIENT_ID;
typedef CLIENT_ID *PCLIENT_ID;

En fonction de ce qu’on veut faire on spécifie ou bien le champ UniqueProcess avec le PID du process visé ou le TID du thread dans UniqueThread. Ensuite le paramètre DesiredAccess contient les droits que le handle devra avoir sur l’objet. Enfin le champ ObjectAttributes n’est quasiment jamais utilisé.

On peut alors se dire que le driver du HIDS va vérifier si on tente d’effectuer un Open* sur une liste de PID/TID, si il detecte une tentative alors il nous envoie balader. Tout le problème est là, comme on ne peut obtenir de handles ni sur le process ni sur ses threads, on est un peu bloqué pour l’injection de code.

Cependant lors de la création d’un process, la fonction CreateProcessInternalW de kernel32 va notifier le subsystem qu’un nouveau process à été crée en appelant CsrClientConnectToServer de ntdll qui va utiliser un LPC sur le port \\Windows\Api. On peut trouver un pseudo-implémentation de ce mécanisme dans le bouquin de Garry Nebbet (Windows 2000 Native Api Reference) au chapitre 6, Processes -> Example 6.1 : Forking a Win32 Process.

/Informs CSRSS about new win32-process
VOID InformCsrss(HANDLE hProcess, HANDLE hThread, ULONG pid, ULONG tid)
{
//        _asm int 3;
    struct CSRSS_MESSAGE {
        ULONG Unknown1;
        ULONG Opcode;
        ULONG Status;
        ULONG Unknown2;
    };

    struct {
                NT::PORT_MESSAGE PortMessage;
        CSRSS_MESSAGE CsrssMessage;
        PROCESS_INFORMATION ProcessInformation;
        NT::CLIENT_ID Debugger;
        ULONG CreationFlags;
        ULONG VdmInfo[2];
    } csrmsg = {{0}, {0}, {hProcess, hThread, pid, tid}, {0}, 0/*STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW*/, {0}};

    CsrClientCallServer(&csrmsg, 0, 0x10000, 0x24);
}

Ici le message est transmit par LPC avec l’API CsrClientCallServer, si on disass CsrClientConnectToServer on voit quelle fait la même opération que le code ci-dessus, tout est donc normal :)

Lorsque csrss.exe recoit ce message il duplique les handles. Ainsi si on regarde le process csrss avec le tool ProcessExplorer on s’apercoit que celui possède des handles sur tout les processes/threads tournant. En fait csrss à en partie pour rôle de deleter les ressources allouer par les process/threads qui sont terminés.

Maintenant on se place dans l’hypothèse ou le HIDS ne contrôle par l’ouverture du handle sur le process csrss.exe (ou même smss son créateur). Nous on veut obtenir un handle sur notre process ou bien sur un de ses threads, il nous suffit donc d’énumerer tout les handles ouvert par csrss puis de retrouver ceux qui font référence notre process. Dès qu’on les a, on les duplique puis on réalise l’injection. C’est bien evidemment cettre dernière feature de Windows qui est si pratique, la duplication nous permet à partir d’un handle sur un process et de celui qu’on vise de crée notre propre handle dans l’ObjectTable de notre process avec les même droits le même objet. De plus les handles passé au process csrss sont avec les droits PROCESS_ALL_ACCESS/THREAD_ALL_ACCESS, on a donc les pleins pouvoirs par la suite :]

Dans mon cas j’ai utilisé une injection de type GhostWriting qui ne nécessite qu’un handle sur un des threads du process visé pour copier et exécuter le code.

Allay la partie technique. Pour commencer il nous faut ouvrir un handle sur le process csrss avec un OpenProcess, mais comme celui-ci tourne sous un autre account (SYSTEM) il nous faut le SeDebugPrivilege. Ensuite on énumère tout les handles ouvert du système en appelant NtQuerySystemInformation avec l’InformationClass sur SystemHandleInformation. De cette liste on extrait les handles ouvert par csrss puis on les duplique dans notre process (NtDuplicateObject) pour pouvoir y retrouver leur type avec NtQueryObject. Si le le type de l’objet référencé par le handle est un thread alors on appel NtQueryInformationThread pour obtenir son TID, si celui-ci correspond au TID du thread primaire du process à injecter alors on effectue un GhostWriting dans sa stack.

Evidemment, ce qui est cool c’est qu’on utilise aucun Open* sur le process à injecter, mais il nous faut être admin sur la b0x pour pouvoir obtenir le SeDebugPrivilege. De plus le HIDS peu très bien checker l’ouverture de handle sur csrss (même si il aussi possible dans ce cas de dupliquer le handle de smss.exe qui à crée csrss.exe)

C:\\ProgHack\\c\\OpenProcesz>t4pZ.exe calc.exe
T4Pz Gh9sTWr1Y1ng
By Ivanlef0u
B3 M4D!
                  ,-~-,       ,-~~~~-,    /\\  /\\
            (\\   / ,-, \\    ,'        ', /  ~~  \\
             \\'-' /   \\ \\  /     _      #  <0 0> \\
              '--'     \\ \\/    .' '.    # =  Y  =/
                        \\     / \\   \\   `#-..O.-'
     Sh1TtInG  >>      O \\   \\   \\  `\\ \\\\
       0n      >>     0    )  />  /    \\ \\\\
       y0u     >>    0o  / /`/ /`__    \\ \\\\__
       T4pZ    >>  o00o (____)))_)))    \\__)))

Csrss.exe PID : 916
calc.exe PID : 1896
calc.exe primary thread TID : 1792
Total Handles : 5683
Thread Handle in Csrss : 948
{*|*} 1nj3ctInG c0de 1n d4 ThR34d {*|*}
[*] pUnctUr3 d0n3 [*]
S33 Y0u M0thAfuK4

Il est bien sur possible que le HIDS contrôle les duplications de handles, mais il faudra que celui fonctionne avec des API comme ObReferenceObjectByHandle et devra manipuler des strutures non documentées (pas officiellement bien sur :}) comme les EPROCES, ETHREADS.

Vous trouvez le code/binaire ici :
http://ivanlef0u.fr/repo/t4pZ.rar

w3 4re 4ll T4pZ h3re, 1′M t4pZ, y0u 4r3 t4pz!
Références :
Windows Internals : Key System Components & Flow of CreateProcess
http://www.phrack.org/archives/62/p62-0x06_Kernel_Mode_Backdoors_for_Windows_NT.txt
http://www.defendion.com/EliCZ/bugs/WinBugs.htm
http://www.c0ding.fr/blog/?p=4

Entry Filed under: Non classé

7 Comments

  • 1. Baboon  |  juin 27th, 2007 at 18:48

    Coucou
    Bravo pour cette technique !
    Tu aurais pu quand meme corriger le ghost writing pour ne pas te faire avoir par kas
    :p
    Ca se fait vraiment en 2 secondes , je ne resiste as a te le mettre en pseudo code :


    mov eax , addrKernel32.section:text
    .scann:
    add eax , 2
    mov dx , WORD [eax]
    and dx , 0xFFF0
    cmp dx , C350
    jne .scann

    movzx edx , BYTE [eax]
    and dl , 0x0F
    cmp dl , 3
    ja .scann

    movzx edx , byte [CONTEXTREG+edx] ;CONTEXTREG etant un tableau de bytes permettant de faire la liaison n° du reg / place du reg dans le context
    mov DWORD [ContextCible + edx] , addrShellCode
    mov DWORD [ContextCible + CONTEXT.eip] , eax

    call SetThreadContext , hThread , ContextCible

    call ResumeThread , hThread

    Bon en fait c’est plus du nasm qu’autre chose …
    T’as plus qu’a traduire en C , chanceux va !


  • 2. admin  |  juin 28th, 2007 at 12:11

    Yo Baboon,
    Dans ton cas tu debug le process avec un DebugActiveProcess puis tu passe ton thread en mode single step, ce qui te permet de pusher ton code dans un zone mémoire allouer. Dans mon cas j’injecte le code dans la stack du thread courant avec un mov [reg1], reg[2] suivit d’un ret qui va tomber dans un 0xEBFE pour se mettre en « attente » puis on reprend le context pour la suite de l’écriture. Donc ta méthode avec les push , ret m’oblige à recoder toute la méthode d’injection et je n’ai pas envie de le faire :P


  • 3. Baboon  |  juin 28th, 2007 at 13:51

    J’ai bien compris la methode d’injection , ne t’en fais pas !!
    dans ce cas il suffit tout simplement de remplacer le tout dernier SetThreadContext
    Comme je suis meugnon tout plein et que j’ai oublie ma clef USB avec tous mes travaux, j’ai du temps :P

    alors il suffit de remplacer cette partie du code de c0de90e7 :

    WorkingThreadContext.Eip=InjectedCodeExecutionStart; // set EIP to the base address where the
    // injected executable code starts ;)

    par :

    long addrKernel32 = (GetModuleHandleA (Kernel32) + 1000)
    long addrJmpEmu = addrKernel32
    for ( addrJmpEmu ; (*addrJmpEmu != 0xC350 ) ; addrJmpEmu++ )

    WorkingThreadContext.Eip = addrJmpEmu
    WorkingThreadContext.Eax = InjectedCodeExecutionStart

    Je ne suis pas sur de la validitée du code mais l’esprit est là :P


  • 4. low_rent_zoo  |  juin 30th, 2007 at 03:07

    Exellent article ivan , mais serieux arrette de pondre tes blabla de  » Salut je mange des chocapics et je cherche a comprendre wtf avec 0×7FFFFFFF  »
    Oseb .
    On veux du bypass constent juste comme celui- ci ! :P

    encore une fois mercay pour ton article ;)


  • 5. newsoft  |  juin 30th, 2007 at 18:45

    « Intellectuellement intéressant ».

    Mais si tu as SeDebugPrivilege, tu peux aussi tuer le process HIDS :)


  • 6. nats`  |  juillet 10th, 2007 at 14:37

    Ouai sauf que la discrétion c’est pas mal non plus ^^


  • 7. elsuk  |  juillet 31st, 2007 at 08:50

    Possible to make function injection??? Not shellcode


Trackback this post


Calendar

mars 2024
L Ma Me J V S D
« fév    
 123
45678910
11121314151617
18192021222324
25262728293031

Most Recent Posts