Archive for juin 27th, 2007

Üb3rGh0stWr1t1nG

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

7 comments juin 27th, 2007


Calendar

juin 2007
L Ma Me J V S D
« mai   juil »
 123
45678910
11121314151617
18192021222324
252627282930  

Posts by Month

Posts by Category