jeudi 21 février 2008

First steps into ring0.

Bonjour à tous,
Je profite de mes petites vacances pour attaquer la programmation de driver.
Cela me trottait dans la tête depuis pas mal de temps enfaite, je vous dévoile alors aujourd'hui mes premier pas dans ce nouveau monde.

Conseils préliminaires :

- Je vous recommande encore une fois, l'utilisation massive de machines virtuels, et de snapshots.
Tout simplement, parce que les Blues Screen Of Death (abrégé BSOD) arrivent très rapidement.

- Ensuite, tout comme dans l'userland (ring3), des outils de debugs sont les bienvenus, je vous conseille donc d'installer les "Debugging Tools for Windows".

- Pour pouvoir mener vos test sur les drivers, je vous recommande "Driver Loader" qui va permettre d'enregistrer votre driver au sein du système.
Vous pouvez ensuite le lancer avec aisance par le biais de la commande "net" :

net start votredriver

Le programme "WinObj" peut aussi vous être utile.

- Et bien sur, le WDK (Windows Driver Kit)!
Cette iso va contenir de la documentation très bien faite, les librairies nécessaires au développement de vos drivers, ..tous ce que vous aurez besoins pour coder vos drivers en tout cas :).
Je cite :

"The Windows Driver Kit (WDK) is a fully integrated driver development system for the Microsoft Windows family of operating systems. It contains the Windows DDK and tests that Microsoft uses to test the stability and reliability of the Windows operating system."
source : http://www.microsoft.com/whdc/devtools/WDK/AboutWDK.mspx.

Voilà tout pour le moment.
Je vous propose à présent, quelques lignes sur la configuration du debuggeur de kernel (kd).


Debug your fucking vm.



Pour pouvoir debugguer vos futurs driver, ou votre kernel, vous avez besoin d'un serveur prêt à être debugguer, ou une machine virtuel.
En ce qui me concerne j'ai choisis la solution machine virtuel, cela est bien plus simple.
Afin de connecter le kd à votre machine virtuel il va falloir tout d'abord ajouter un Port série à votre vm.



On choisit ensuite de faire transiter les données par un named pipe.




On configure la connection de la named pipe avec le port série.




N'oublions pas de cliquer sur le bouton "Advanced" et de cochez "Yield CPU on poll".
Une fois configurer notre port série, on va modifier un petit peu le boot.ini pour que la machine supporte le remote debugging.
Vous ouvrez donc le boot.ini avec notepad++ par exemple, vous copiez collez la ligne dans le [Operating systems] qui existe déjà, vous vous retrouvez avec deux lignes identiques.
Vous rajoutez sur l'une des deux cela :

/debug /debugport=COM1:

Je me retrouve avec un boot.ini qui ressemble à cela :

multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professionnel" /noexecute=optin /fastdetect /kernel=oemkrnl.exe
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professionnel" /noexecute=optin /fastdetect /kernel=oemkrnl.exe /debug /debugport=COM1:

A présent, on redemare notre vm..et là au boot, nous avons le choix entre un démarrage classsique, et un démarrage avec le debug activé!



Il est temps de sortir WinDbg.
Vous allez dans le menu "File"->"Kernel Debug" et on va le configurer pour que les données entre la vm et le debug transite par le named pipe.




On valide, et Break (CTR+Break), et vous devriez vous retrouvez avec le prompt du kd.




Je vous conseil aussi de télécharger les symbols : http://msdl.microsoft.com/download/symbols.
Ensuite vous vous creez une variable d'environnement qui porte le nom :

_NT_SYMBOL_PATH

et comme valeur :

SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols

Vous êtes donc prêt à debugguer vos drivers !
Ceci dit je vous donne un peu de documentations :

- Si vous voulez connecter virtualpc a windbg -> http://therecyclebin.wordpress.com/2007/06/11/kernel-debugging-windbg-and-virtual-pc/.
- Windbg -> http://software.rkuster.com/.
- WDK -> http://connect.microsoft.com/.

Introduction

"One Ring to rule them all, One Ring to find them, One Ring to bring them all and in the darkness bind them." The Fellowhip of the Ring, J. R. R. TOLKIEN.


Je vais consacrer ces quelques lignes à présenter un peu le ring0.
Comme vous le savez peut être déjà tous, les processeurs mettent à disposition 4 niveaux de privilèges appelés rings (ring0 , .. , ring3).
Le système windows en utilise que deux d'entre eux à savoir :

- L'userland ou le ring3 (abrégé r3).
- Et le kerneland ou le ring0 (abrégé r0).

Le ring0 va permettre la gestion de la mémoire virtuelle par exemple, ou encore la gestion d'un matériel connecté à votre ordinateur ; c'est enfaite le coeur du système.
Comme la citation le laisse entrevoir, dans le ring0 c'est nous le maître :).
En revanche le ring3 est ce qui est le plus classique, les exécutables classiques, notre bon vieux client irc, ou notre player de musique préférée ; ceci dit cette espace est restreint à des règles.




On retrouve souvent le fonctionnement suivant : une application est exécutée depuis l'userland, celle-ci va envoyer des informations à un driver qui lui va pouvoir agir en conséquence, en lui renvoyant si nécessaire des informations de retours.

If faut savoir aussi que la taille des registres de nos processeurs s'élève à 32bits (architecture x86), nous avons donc accès a 2^32 adresses mémoire, soit 4go : 2 pour l'userland (de 0x00000000 à 0xBFFFFFFF) et 2 pour le kerneland (de 0xC0000000 à 0xFFFFFFFF).

A présent notre but va être de coder des programmes capables de survivre dans ce monde où il n'est question que de BSOD (mais nan :)).
On appellera ces programmes des drivers.

Et pourquoi pas arriver vers un rootkit de base commandé de l'userland ? :).
Place au coding à présent.


Message venu du nouveau monde.


Après cette brève introduction au ring0, nous allons pouvoir aborder la programmation de driver.
Le point d'entré d'un driver est celui-ci :

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath)
{
}

Avec pDriverObject qui est un pointeur sur une structure du type DRIVER_OBJECT.
Celle-ci représente le driver chargé, et le second argument pRegistryPath est une chaine de caractères UNICODE de la forme suivante :

\Registry\Machine\System\CurrentControlSet\Services\NomDuDriver

Ensuite si vous voulez déchargez un driver, il faut spécifier une fonction d'unload par le biais du membre DriverUnload de la structure DRIVER_OBJECT.

pDriverObject->DriverUnload = VotreFonction;

Et enfin, on utilise l'équivalent de printf() mais au niveau kerneland à savoir : DbgPrint().
Les messages seront bien sur visible grâce à un outil utilisé dans des articles précédents : DebugView.
Ceci nous amène donc à la compilation!

Euh..On compile cela comment?

J'y viens.:)
Tout d'abord j'utiliserais le compilateur disponible avec le wdk, cela évitera de se casser la tête.
Deux fichiers sont nécéssaires à la compilation :

- le makefile.
- et un fichier "sources" (c'est enfaite le nom des fichiers de projets sous le wdk).

Le fichier makefile est composé d'une seule ligne :

!INCLUDE $(NTMAKEENV)\makefile.def

Ensuite le fichier sources est décomposé de la façon suivante :

TARGETNAME = LeNomDuDriver
TARGETPATH = obj
TARGETTYPE = DRIVER

INCLUDES = %BUILD%\inc
LIBS = %BUILD%\lib

SOURCES = VotreSource.c

Nous sommes donc prêt à compiler notre premier driver, émotion au rendez vous !
Nous ouvrons le build environment xp.
On se déplace dans notre dossier contenant les trois fichiers, et on lance la commande build.
Oh..un .sys :), il s'agit de notre driver.

Mais comment le lance t-on?

Patience, nous y voilà.
Dans les premières lignes de ce modeste article, je vous proposais plusieurs outils, dont DriverLoader.
DriverLoader va nous permettre d'enregistrer notre driver, et de pouvoir le lancer.
Nous demarrons DebugView, on lance DriverLoader, et on lance notre driver.



Et voilà, notre helloWorld fonctionne :).
A présent, just for phun, nous allons provoquer un BSOD, histoire d'en réver pendant une semaine.
On va aller écrire n'importe quoi à n'importe qu'elle adresse enfaite :).
Resultat en image :



Enfin bon, a présent passons aux choses sérieuses.


E.T téléphone kernel.


Maintenant notre but va être de faire communiquer une application lancée en ring3 et un driver en ring0.
Nous commencerons par le driver.
Pour mener à bien notre quête, nous allons utiliser les IOCTLs codes et les IRPs.
Mais nous en parlerons un peu plus bas.
Afin de pouvoir communiquer avec l'exterieur, nous avons besoin de creer un "device" une sorte d'interface.

NTSTATUS
IoCreateDevice(
IN PDRIVER_OBJECT DriverObject,
IN ULONG DeviceExtensionSize,
IN PUNICODE_STRING DeviceName OPTIONAL,
IN DEVICE_TYPE DeviceType,
IN ULONG DeviceCharacteristics,
IN BOOLEAN Exclusive,
OUT PDEVICE_OBJECT *DeviceObject
);

N'oublions pas que les chaines mis en jeux sont des chaines unicodes.
Ensuite il est nécéssaire de creer un symlink entre le nom de notre interface, et le nom visible de l'userland.
Ce symlink permettra d'avoir accès à notre device depuis le r3.

NTSTATUS
IoCreateSymbolicLink(
IN PUNICODE_STRING SymbolicLinkName,
IN PUNICODE_STRING DeviceName
);

Après ces étapes, nous allons "handler" des fonctions à déclencher selon la réception des différentes IRP.
Je m'explique, une IRP est enfaite un paquet d'information envoyé à un driver, il existe plusieurs type d'IRP (voir documentation).

A l'intérieur de la structure DRIVER_OBJECT il existe un membre nommé MajorFunction qui est tableau de pointeur.

kd> dt nt!_DRIVER_OBJECT
+0x000 Type : Int2B
+0x002 Size : Int2B
+0x004 DeviceObject : Ptr32 _DEVICE_OBJECT
+0x008 Flags : Uint4B
+0x00c DriverStart : Ptr32 Void
+0x010 DriverSize : Uint4B
+0x014 DriverSection : Ptr32 Void
+0x018 DriverExtension : Ptr32 _DRIVER_EXTENSION
+0x01c DriverName : _UNICODE_STRING
+0x024 HardwareDatabase : Ptr32 _UNICODE_STRING
+0x028 FastIoDispatch : Ptr32 _FAST_IO_DISPATCH
+0x02c DriverInit : Ptr32 long
+0x030 DriverStartIo : Ptr32 void
+0x034 DriverUnload : Ptr32 void
+0x038 MajorFunction : [28] Ptr32 long

Ce tableau nous permet alors d'handler des fonctions qui vont réagir selon les différentes IRPs reçus.

Par exemple, lorsque l'on va ouvrir un handle sur notre device (dans notre application ring3) par le biais de la fonction CreateFile(), le driver va recevoir
une IRP_MJ_CREATE, et quand on va fermer le handle, il va recevoir une IRP_MJ_CLOSE.

C'est ici que les IOCTLs rentrent en jeux.
En effet pour pouvoir déclencher tel ou tel action, nous avons besoin d'une sorte de "code" qui serait recuperé par le driver, et qui agirait en conséquence.
Nous allons donc forger des IOCTLs, par le biais de la macro CTL_CODE().
On va donc creer notre propre "code" qui sera reconnus par le driver.

#define IOCTL_LOL\
CTL_CODE( SIOCTL_TYPE, 0x800, METHOD_BUFFERED, FILE_READ_DATA|FILE_WRITE_DATA)

par exemple.
Il faut savoir qu'il existe plusieurs type de transfert pour nos données, en ce qui nous concerne nous utiliserons la METHOD_BUFFERED.

Bon à présent lors de l'envoi de l'IOCTL par notre appli r3, le driver va alors recevoir une IRP_MJ_DEVICE_CONTROL.
La fonction qui sera "handler" à cette irp va alors s'occuper de récuperer des informations sur le type d'IOCTL reçus.
Pour cela nous utiliserons la fonction suivante :

PIO_STACK_LOCATION
IoGetCurrentIrpStackLocation(
IN PIRP Irp
);

Cette fonction va permettre de récupérer tous ce dont on aura besoin sur l'action demandée.
Ensuite nous allons lire le membre Parameters.DeviceIoControl.IoControlCode de la structure IO_STACK_LOCATION.
Ce membre nous indique le "code" envoyé : celui forgé ; notre IOCTLs.
Il nous reste plus qu'a mettre en place un switch sur ce membre, et agir en conséquence :).
Il est aussi possible de passer des arguments, il suffit de lire le membre AssociatedIrp.SystemBuffer de la structure IRP et d'y écrire dedans.
Ce buffer fait office de buffer d'entré et de sortie, mais ceci est propre à la METHOD_BUFFERED.


Screenshot pour la route :



On peut aussi à ce moment là, utiliser l'outil WinObj pour constater l'existence de notre device avec un symlink.



Ouf, vous pouvez soufler un peu, nous arrivons à la fin.
Comme vous vous en doutez surrement, ces IOCTLs vont donc être massivement employer dans les rootkits par exemple, afin de faire communiquer le driver et l'application userland.

Pas d'exemple concret?:(

Mais si!


How to hide a fucking process with DKOM (Direct Kernel Object Manipulation).


Dans cette partie nous allons nous amusez à cacher un processus au système :).
Je vous explique un peu notre plan :

- Notre application userland, va recuperer le nom du processus que l'on veut cacher.
- L'appli va envoyer une IOCTL au driver, avec un argument : le nom du processus.

- Le driver va donc recuperer le nom du processus. (c'est là que ça devient intéréssant)
- Nous allons récupérer un pointeur sur une structure EPROCESS grâce à la fonction IoGetCurrentProcess().
- Une fois récupérer notre pointeur, nous allons parcourir les structures grâce au membre ActiveProcessLinks qui est enfaite une double liste chainée.
- Nous allons comparer le nom du processus récupéré avec le membre ImageFileName.
- Si il n'y a aucune différence nous nous trouvons dans la structure EPROCESS concernant le processus à cacher.
- A présent il nous reste juste à modifier la structure précédente et suivante afin que les membres Flink et Blink des listes chainées ne pointent plus sur la structure du processus à caché.
On va en quelques sortes "sauter" la structure à caché.

Voilà à présent je vous file 2 structures qui vont être utile dans la compréhension du code :

kd> dt nt!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x06c ProcessLock : _EX_PUSH_LOCK
+0x070 CreateTime : _LARGE_INTEGER
+0x078 ExitTime : _LARGE_INTEGER
+0x080 RundownProtect : _EX_RUNDOWN_REF
+0x084 UniqueProcessId : Ptr32 Void //PID du processus, à l'offset 0x084.
+0x088 ActiveProcessLinks : _LIST_ENTRY //ce qui nous interesse :)) à l'offset 0x088.
+0x090 QuotaUsage : [3] Uint4B
+0x09c QuotaPeak : [3] Uint4B
+0x0a8 CommitCharge : Uint4B
+0x0ac PeakVirtualSize : Uint4B
+0x0b0 VirtualSize : Uint4B
+0x0b4 SessionProcessLinks : _LIST_ENTRY
+0x0bc DebugPort : Ptr32 Void
+0x0c0 ExceptionPort : Ptr32 Void
+0x0c4 ObjectTable : Ptr32 _HANDLE_TABLE
+0x0c8 Token : _EX_FAST_REF
+0x0cc WorkingSetLock : _FAST_MUTEX
+0x0ec WorkingSetPage : Uint4B
+0x0f0 AddressCreationLock : _FAST_MUTEX
+0x110 HyperSpaceLock : Uint4B
+0x114 ForkInProgress : Ptr32 _ETHREAD
+0x118 HardwareTrigger : Uint4B
+0x11c VadRoot : Ptr32 Void
+0x120 VadHint : Ptr32 Void
+0x124 CloneRoot : Ptr32 Void
+0x128 NumberOfPrivatePages : Uint4B
+0x12c NumberOfLockedPages : Uint4B
+0x130 Win32Process : Ptr32 Void
+0x134 Job : Ptr32 _EJOB
+0x138 SectionObject : Ptr32 Void
+0x13c SectionBaseAddress : Ptr32 Void
+0x140 QuotaBlock : Ptr32 _EPROCESS_QUOTA_BLOCK
+0x144 WorkingSetWatch : Ptr32 _PAGEFAULT_HISTORY
+0x148 Win32WindowStation : Ptr32 Void
+0x14c InheritedFromUniqueProcessId : Ptr32 Void
+0x150 LdtInformation : Ptr32 Void
+0x154 VadFreeHint : Ptr32 Void
+0x158 VdmObjects : Ptr32 Void
+0x15c DeviceMap : Ptr32 Void
+0x160 PhysicalVadList : _LIST_ENTRY
+0x168 PageDirectoryPte : _HARDWARE_PTE
+0x168 Filler : Uint8B
+0x170 Session : Ptr32 Void
+0x174 ImageFileName : [16] UChar //Nom du process
+0x184 JobLinks : _LIST_ENTRY
+0x18c LockedPagesList : Ptr32 Void
+0x190 ThreadListHead : _LIST_ENTRY
+0x198 SecurityPort : Ptr32 Void
+0x19c PaeTop : Ptr32 Void
+0x1a0 ActiveThreads : Uint4B
+0x1a4 GrantedAccess : Uint4B
+0x1a8 DefaultHardErrorProcessing : Uint4B
+0x1ac LastThreadExitStatus : Int4B
+0x1b0 Peb : Ptr32 _PEB
+0x1b4 PrefetchTrace : _EX_FAST_REF
+0x1b8 ReadOperationCount : _LARGE_INTEGER
+0x1c0 WriteOperationCount : _LARGE_INTEGER
+0x1c8 OtherOperationCount : _LARGE_INTEGER
+0x1d0 ReadTransferCount : _LARGE_INTEGER
+0x1d8 WriteTransferCount : _LARGE_INTEGER
+0x1e0 OtherTransferCount : _LARGE_INTEGER
+0x1e8 CommitChargeLimit : Uint4B
+0x1ec CommitChargePeak : Uint4B
+0x1f0 AweInfo : Ptr32 Void
+0x1f4 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
+0x1f8 Vm : _MMSUPPORT
+0x238 LastFaultCount : Uint4B
+0x23c ModifiedPageCount : Uint4B
+0x240 NumberOfVads : Uint4B
+0x244 JobStatus : Uint4B
+0x248 Flags : Uint4B
+0x248 CreateReported : Pos 0, 1 Bit
+0x248 NoDebugInherit : Pos 1, 1 Bit
+0x248 ProcessExiting : Pos 2, 1 Bit
+0x248 ProcessDelete : Pos 3, 1 Bit
+0x248 Wow64SplitPages : Pos 4, 1 Bit
+0x248 VmDeleted : Pos 5, 1 Bit
+0x248 OutswapEnabled : Pos 6, 1 Bit
+0x248 Outswapped : Pos 7, 1 Bit
+0x248 ForkFailed : Pos 8, 1 Bit
+0x248 HasPhysicalVad : Pos 9, 1 Bit
+0x248 AddressSpaceInitialized : Pos 10, 2 Bits
+0x248 SetTimerResolution : Pos 12, 1 Bit
+0x248 BreakOnTermination : Pos 13, 1 Bit
+0x248 SessionCreationUnderway : Pos 14, 1 Bit
+0x248 WriteWatch : Pos 15, 1 Bit
+0x248 ProcessInSession : Pos 16, 1 Bit
+0x248 OverrideAddressSpace : Pos 17, 1 Bit
+0x248 HasAddressSpace : Pos 18, 1 Bit
+0x248 LaunchPrefetched : Pos 19, 1 Bit
+0x248 InjectInpageErrors : Pos 20, 1 Bit
+0x248 VmTopDown : Pos 21, 1 Bit
+0x248 Unused3 : Pos 22, 1 Bit
+0x248 Unused4 : Pos 23, 1 Bit
+0x248 VdmAllowed : Pos 24, 1 Bit
+0x248 Unused : Pos 25, 5 Bits
+0x248 Unused1 : Pos 30, 1 Bit
+0x248 Unused2 : Pos 31, 1 Bit
+0x24c ExitStatus : Int4B
+0x250 NextPageColor : Uint2B
+0x252 SubSystemMinorVersion : UChar
+0x253 SubSystemMajorVersion : UChar
+0x252 SubSystemVersion : Uint2B
+0x254 PriorityClass : UChar
+0x255 WorkingSetAcquiredUnsafe : UChar
+0x258 Cookie : Uint4B

kd> dt nt!_LIST_ENTRY
+0x000 Flink : Ptr32 _LIST_ENTRY //Pointe sur la struct suivante.
+0x004 Blink : Ptr32 _LIST_ENTRY //Pointe sur la struct precedente.

Je pense que vous êtes apte à comprendre le code fournis :).

Un petit screenshot pour la route :



A présent il nous reste à aborder l'application ring3.
Celle-ci est extremement simple à comprendre/coder.
En effet, on ouvre un handle sur notre device avec CreateFile(), nous envoyons nos IOCTLs grâce à la fonction DeviceIoControl().
Voilà tout!

Et je compile ça comment?

J'ai utilisé le compilateur disponible dans le wdk.
Seul le fichier "sources" diffère, je vous propose le mien :


TARGETNAME=votreAppli
TARGETTYPE=PROGRAM

INCLUDES=

SOURCES=VotreAppli.c

UMTYPE=console
UMBASE=0x04000000

USE_MSVCRT=1


Vous pouvez dorénavant compiler l'application utilisé pour communiquer avec notre driver !

Mais..cette technique n'a pas de "point" faible?

Hum, à mon grand regret après avoir lus un article disponible sur le blog d'un amis (lilxam), celui-ci nous montre comment "bypasser" ce hide de process :).
Enfin bon, je ne m'avous pas vaincus, je reviendrais avec une meilleure technique :))).

Il est venus le temps de filer les codes :

- HelloWorld.c
- BSOD.c

- HideFuckingProcessR3.c
- HideFuckingProcessR0.c

Et voilà c'est finit pour aujourd'hui !
Encore merci aux personnes qui m'auraient filer un coup de main et toussa :).
cya.

PS : Achetez vous "Subverting kernel windows" écrit par le créateur rootkit.com, un superbe livre de chevet :).

samedi 16 février 2008

3v1l 0r n0t ? - Part II.

Bonjour à tous,

je release aujourd'hui la seconde et dernière partie de mon analyse.

Souvenez vous que lors du précédent article, nous nous étions arrêté à la connection sur un serveur irc.

Au cours de cet article je vais vous présenter rapidement les fonctions que le codeur a intégré au seins de son malware.


Conseils préliminaires :


-Cette fois-ci, l'accès au net est bien entendu nécessaire, des outils comme Wireshark ainsi que ProcessExplorer peuvent être utiles, histoire de surveiller les threads de notre processus, et de vérifier les accès au réseau de notre programme.

-Dans cette partie, je vous conseil de vous débrouiller afin que le malware ne se connecte pas sur le serveur « normal ». Redirigez le vers un serveur où vous le rejoindrez pour mener vos tests.

On modifie alors les variables nécessaires, on utilise le clic droit->Follow In Dump sous OllyDbg.

Je pense avoir à peu près tout dis.

Place à l'analyse à présent.


Pourquoi l'irc?


Cela est peut être une question que vous vous posez.

La connection de la victime sur un serveur irc présente en fait plusieurs avantages.

Tout d'abord, l'attaquant n'a alors aucune connection directe avec sa ou ses victimes, les serveurs où les logs sont inexistants sont donc très intéressants.

De plus, le faite de ce connecté à un serveur irc, permet de passer outre le problème des routeurs, avec le forwarding de port.

Enfin, dans ce genre de cas, je pense que si l'attaquant utilise l'irc c'est évidemment pour commander toutes ses victimes avec aisance.

Dans ce cas précis, le « gérant » du serveur, utilisait un script permettant de contrôler le reseau de zombie, en envoyant à intervalle de temps régulier des commandes.

Une commande est alors exécutée par toutes les victimes présentes sur le channel.

Cette « technique » est souvent utilisée pour commander des attaques de type « Distributed Denial of Service » par exemple.


Tr4c3 m3.


Nous voilà repartis dans les profondeurs de notre exécutable.

En plus de la connection à un serveur irc, on observe bien sûr plusieurs modules, comme un module de réponse au PING ( voir rfc irc ), un module permettant de rejoindre le channel si l'on été kicker etc.

Cependant, une chose nous attire l'oeil, après avoir traité les cas précédents, on call une fonction.

Le mystère est alors entier.

On trace, on trace, c'est alors que nous remarquons deux choses intéréssantes.

On va pusher une chaîne de caractères, notre buffer ( découpé par une routine bien evidémment ) et bien sûr un call à la fonction strstr() disponible dans la librairie string.h.


Mais que cherche t-il a faire?


C'est pourtant très simple, ceci est une façon de commander la victime présente sur le channel.

En effet dans le premier cas, on « déclenche » une fonction si l'on trouve la chaine « òÿööõ ».


Chaine1 :

db 0F2h

db 0FFh

db 0F6h

db 0F6h

db 0F5h

db 0


Intéressons nous à cette routine.


A fucking Thread


Comme toujours nous traçons, nous traçons.

Cette routine est plutôt longue et assez complète c'est pour cela que j'en parlerai brièvement.


On va donc au début de cette routine effectuer un test, en ce qui concerne la langue utilisée sur le système corrompu, afin de pouvoir sélectionner un message qui sera en accord avec la langue.

On commence déjà, a sentir ce qui nous attend.

Plus bas,nous arrivons sur la routine qui va se charger de « manipuler » msn, afin de se propager en envoyant un message contenant un lien, aux adresses contenues sur le compte de la victime.


On aperçoit ensuite un appel à CreateThread(), serait-ce le thread qui va se charger de manipuler msn?


On va bien sûr poser un breakpoint sur le début de la routine afin de pouvoir l'analyser.

En traçant, on observe des chaînes de caractères qui nous ne sont pas méconnues, comme : « C'est pas toi??!!! ».

On peut supposer que ces messages correspondent à ce qui sera envoyé aux contacts.

Bon, on comprend aussi que le malware va utiliser la COM library pour corrompre msn, les appels aux fonctions CoInitialize() et CoCreateInstance() nous confortent donc notre analyse.


Après de multiples actions, on va formater une chaîne de caractères composée du message dans la bonne langue, ainsi qu'un lien, afin de faire télécharger un exécutable à la victime.

On peut donc « personnaliser » ce lien, il suffit d'appeler la fonction avec la chaine de caractères : « òÿööõ » suivit d'une url xorée avec la clé 196.


Exemple :

Les messages que nous recevons sont du type :

« C'est pas toi?!!!!http://membres.lycos.fr/photoos2008/?=votreadressemsn »

La commande envoyée par l'attaquant est donc :

« òÿööõ ¬°°´þëë©¡©¦¶¡·ê¨½§«·ê¢¶ë´¬«°««·öôôüëûù »


Une fois la chaîne formatée, concaténée avec votre adresse, le malware va utiliser une technique plutôt « maison » si je peux dire.

En effet, il va se servir du clipboard.

Il va tout simplement copier la chaîne de caractères dans le clipboard.


Hum, a quoi cela sert-il?


Le malware, va alors se débrouiller pour cacher la fenêtre du contact de la victime et lui donner le focus.

Patience, juste en dessous, on aperçoit des appels à une fonction : keybd_event().

On regarde les arguments qui lui sont passés. La première fonction va simuler l'appuis sur la touche « CTRL », la seconde sur la touche « V » et la dernière sur la touche « ENTER ».

Une petite astuce qui peut être retenue !

Utiliser le clipboard pour stocker une information et utiliser le raccourcis clavier, simulés par keybd_event(), pour coller l'information.


Voilà en ce qui concerne la première commande.


Finalement il nous reste à en savoir plus sur la seconde commande.

Celle-ci est déclenchée par la chaîne de caractères : « ôóýýûòó ».


Chaine2 :

db 0F4h

db 0F3h

db 0FDh

db 0FDh

db 0FBh

db 0F2h

db 0F3h

db 0


Bon après avoir tracer cette routine, elle reste très similaire à la première.

Tous d'abord cette fonction à été créée je pense, afin de pouvoir personnaliser les messages envoyés, aux victimes.

Afin d'éviter de toujours utiliser les chaînes de caractères hardcodées.

On peut donc appeler la fonction de la façon suivante :


Exemple :

« ôóýýûòó 0vercl0k.blogspot.com/?= plz look» cette commande ira envoyer le message : « plz look 0vercl0k.blogspot.com/?=votreadressemsn ».


Bien sûr, les chaînes de caractères doivent être xorée avec la clé 196 avant d'être passée en argument, je ne l'ai pas « encodée » pour faciliter la compréhension.


Donc le thread lancé par la commande est le même.

Les deux fonctions sont quasiment identiques, seulement dans la seconde fonction on constate la présence d'une routine se chargeant de « découper » le buffer en argument, pour ensuite les passés à la commande.


Conclusion


L' analyse de ce malware est alors terminé en ce qui me concerne.

Je n'analyserais pas les binaires qui ont été télécharger par le programme au fur et a mesure de l'exécution du malware, tout simplement car cela me prend énormément de temps.

Tous ce que je sais, c'est que les exécutables vont entre autre en télécharger d'autre binaire, certains sont contenus dans des pages phps, on pourrait même croire à une sorte de serveur qui stock des améliorations ou autres, un serveur d'update.

Bon après cette partie, je vous propose une petite excursion.


Sh3rl0ck h0lm3s


Une fois que j'étais au courant de ce que pouvais faire le malware, la curiosité m'a poussé à aller sur le serveur où le malware est censé se connecter.

La connection s'effectue..

Je décide alors de me faire passer pour une victime, je prend un nick formaté comme celui d'une victime.

Petit temps de repérage, le serveur est loin d'être bavard, presque toutes les commandes sont désactivés, les whois sont interdits, aucun voicé, le channel est modéré.

Le channel est en apparence vide, les victimes sont surrements cachées, je vois seulement un opérateur.

Celui-ci balance sur le public une chaine du style :


òÿööõ ¬°°´þëë©¡©¦¶¡·ê¨½§«·ê¢¶ë´¬«°««·öôôüëûù


On reconnaît bien sure la première commande, si l'on décrypte la chaine on retrouve : « http://membres.lycos.fr/photoos2008/?= »


Enfin bref, cela m'intrigue, ce qui m'étonnerai serai que le serveur qui héberge le daemon irc, appartienne au codeur du malware.


Avec l'aide de sevieron, nous entamons une petite, analyse.

On commence notre analyse, par un whois sur le dns asl.aldanma.net.


[...]
Domain Name.......... aldanma.net
Creation Date........ 2005-07-26
Registration Date.... 2005-07-26
Expiry Date.......... 2010-07-26
Organisation Name.... Marsha Grizzell
Organisation Address. 220 montalvo dr
Organisation Address.
Organisation Address. bakersfield
Organisation Address. 93309
Organisation Address. CA
Organisation Address. UNITED STATES MINOR OUTLYING ISLANDS
[...]


On lance quelques recherches, afin de trouver quelques informations sur la soit disant propriétaire.

Google nous renvois des sites ayant un rapport avec des produits pour la perte de poids, par exemple healthweight.ne, assez étonnant qu'un daemon irc installé, dans le but de récupérer et commander les victimes, par une tel personne.
Nous continuons.
C'est à présent un scan, que nous lançons sur le serveur.

[...]
PORT STATE
80/tcp closed
83/tcp open
358/tcp open
3389/tcp open
8721/tcp open
[...]

Nous tentons une connection sur le port tcp 8721.



Nous tombons sur une petite surprise, on se retrouve sur un espèce de remote shell/ftp daemon.
L'identification se passe comme un daemon ftp apparemment.

USER anonymous
PASS lolilol@lolilol.com

Bon, fallait s'en douter, l'accès est (heureusement) refusé.
Le but de l'opération ne résidait de toutes façons pas en l'obtention d'un accès.
Nous avons cependant observer des phrases présentes dans la « présentation » à la connection.
D'après Google il s'agit d'un trojan qui permettrait d'upper des fichiers et j'en passe.
Ce qui confirmerais qu'il agit bien d'un serveur compromis.

PS : Un windows server 2003 tourne sur le 3389.
Tout cela, pour montrer que la prise d'information sur un serveur est d'après moi, essentiel pour la suite des opérations.

On peut donc aussi conclure que le serveur a surement été victime d'une attaque quelconque, menant à un remote access.


Voilà nous arrivons à la fin de ce petit article.
J'espère avoir intéressé quelques d'entres vous, je vous donne quelques liens :

Analyser un binaire rapidement et autre qu'en local -> http://analysis.seclab.tuwien.ac.at/index.php.
LE scanner -> http://nmap.org/.
L'archive mise à jour contenant les binaires, .idbs -> http://overclok.free.fr/Codes/AnalyseMalwareNaked/Analyse_Malware_Naked.rar

C'est finit, bonne journée à tous.
Remerciement, aux personnes qui me relisent, et qui me conseil, voilà tout est dit :).
Cya.

samedi 2 février 2008

3v1l 0r n0t ? - Part I.

Bonjour à tous,
Me revoilà avec un petit article, celui-ci traitera de l’analyse d’un malware récent : naked.com.
Cette analyse m’a prit pas mal de temps en effet, j’y est donc consacré deux semaines (ce qui explique l’absence de post la semaine dernière).
Ceci dit, celui-ci sera un peu plus long.

Conseils préliminaires :

-Tous d’abord, si vous comptez lancer le vers, munissez vous d’une machine virtuel (vmware par exemple).
Personnellement j’ai utilisé vmware, avec une machine virtuel où j’y ai installé Windows.

-Ensuite je vous conseil d’utiliser la fonction ’snapshot’ de vmware, celle-ci permet de prendre une image du système tel que, au cas ou vous voudriez revenir avec un système vierge de toute infection, on charge l’image de notre Windows et nous revoilà avec un système vierge.

-De plus, des outils sont nécessaire pour analyser un peu le malware, on ne peut pas se passer de désassembleur et d’un débuggeur bien évidemment.
En ce qui me concerne, j’utiliserais IDA ainsi qu’OllyDbg en tant que débuggeur.
Je voulais aussi ajouter que IDA est vraiment un outil, tout simplement merveilleux. Ce qu’il apporte en plus, c’est tout d’abord la possibilité de renommer les variables, les fonctions et j’en passe.
Le dump devient de plus en plus lisible, car il vous appartient!
Profitez pleinement de ce gros avantage.
Mais on peut citer des outils, comme RegMon , snort, ProcessExplorer, ou encore Wireshark, sans oublier les exécutables natifs comme regedit.
Ceci dis, si vous avez confiance en vous et en votre analyse, le débuggeur et le désassembleur suffira .

-Une dernière petite chose qu’il faut à mon goût penser, c’est que nous partons sur la base que l’exécutable à analyser peut faire n’importe quoi ; c’est pour cela je vous conseil de désactivé l’accès à tous types de réseaux, que ce soit un réseau local ou autres.

Je pense avoir résumé le tout, vous êtes à présent apte à analyser un petit malware.

Je tiens à préciser que je ne fournirais aucun binaire relatif à mon analyse, afin d’éviter toutes détériorations massives par des kiddies ou autres.
Au cours de ce petit post, je vais présenter les actions de notre petit malware.
Si il y a des passages où l’analyse est erroné, n’hésiter pas à prendre contact avec moi, il s’agit de ma première analyse de malware.

Je vous file quelques petits papers qui peuvent être intéressant à lire avant :

-http://www.netix.free.fr/tutos/ida/ida1/ida1.htm -> prise en main d’IDA.
-http://milw0rm.com/papers/133 -> Anatomy of a Malware, ce pdf vous présente une analyse concrète avec dumps.

Après c’est quelques avertissements, nous allons pouvoir attaquer le vif du sujet.

Premier contact avec le loader.

Nous allons tout d’abord vérifier si notre exécutable est protégé contre le reversing.
Il peut être en effet packer, ce qui peut nous gêner au cours de notre analyse.
Je lance un coup de PEID sur l’exécutable.




Je vais donc aller, regarder du côté des sections de l’exécutable et là..



Le nom des sections est UPX0 etc. En tant qu’être normalement constitué, je télécharge le packer UPX, et puis je le test avec sa fonction d’ unpack sur mon exécutable.
Je relance PEID, pour voir si ce n’était pas un vilain trick du codeur.





Le ton est a priori donné, nous allons débuguer/désassembler un code C/C++, une bonne nouvelle me direz vous.

Trip in da binaire

Et nous voilà partis, IDA d’un côté, et Olly de l’autre, nous sentons l’adrénaline qui monte, let's go !!
Dès le début de notre analyse, on remarque des actions plutôt bizarre : on se retrouve avec des appels aux apis GetTickCount et Sleep().
C’est à ce moment là que l’on se demande a quoi il joue : c’est en faite très simple, il s’agit d’un anti-debug (abrégé anti-dbg ).
Si l’exécutable est debuggué il se peut, que vous allez rester du temps sur une instructions, or si le sleep dure plus de temps (millisecondes) que celui demandé, on se retrouvera avec une différence de seconde!
Bon, un petit anti-dbg qui vaut pas grand-chose à mon avis, continuons.
Nous tombons, sur une routine qui va décrypter une chaîne de caractères : c’est enfaîte un xor de la lettre avec le nombre 139.
Un petit code C est fournis en fin d’article pour décoder ce genre de chaîne.
Nous avançons, on manipule des structures du type PROCESS_INFORMATION et STARTUPINFO, on flag les structures de façons a avoir une fenêtre caché, si un éventuel appel à CreateProcess.
On récupère à présent le path sur le dossier temporaire de la bécane, grâce à GetTempPath(), c’est un peu plus loin que l’on va formater une chaîne de caractère du type : DossierTemporaire\services.exe.
On se doute que ce fichier sera, le cœur de notre ver.
Nos petites suppositions était loin d’être fausse, car le loader va créer ce fichier dans le dossier temporaire justement, on y écris le code binaire qui est stocké dans le loader.
On lance alors le processus, services.exe, précédemment créer (d’où le flag des structures etc.).

Nous voilà déjà avec un binaire pas très gentil (supposons) de créer, et de lancer.
Continuons!

Afin de ne pas alerter la victime, le loader va tout d’abord, créer un fichier image.jpg dans le dossier courant, pour après allez l’afficher dans une fenêtre.
Me direz vous, il faut pas être très fin pour ne pas se douter de quelque chose, mais passons.
Voilà, le loader s’arrête ici.
A présent, analysons services.exe.

Services.exe, un parfait cachottier.

De retour, accompagné de nos fidèles instruments.
Petit reflex, vérifié si l’exécutable n’est pas protégé.



Première chose que nous remarquons d’intéressants, c’est bien sure l’appel à deux calls.
On s’engage droit dedans, on trace, on trace, de call en call, les routines s’éclaircissent.
On comprend peu à peu qu’il s’agit enfaîte des routines qui se chargent de décrypter toutes les chaînes dont le programme aura besoin.
Et cela, grâce a un xor de la lettre et du chiffre 7 cette fois-ci.
Le programme fait ensuite appel aux APIs GetProcAddress et GetModuleHandle afin de récupérer l'adresse des API qui lui seront utile par la suite.
Une fois ceci effectué, on constate une injection de code dans l’explorer.exe!
Rien de bien croustillant, juste un control au niveau de la mutes ainsi qu’un WinExec sur le services.exe justement.
On ne se décourage, on continus.
Cette fois-ci nous arrivons sur une récupération de pointeur sur la fonction InternetReadFile exportée par WinInnet.dll, on génère ensuite une chaîne de caractères de 6lettres, et là.. On télécharge un fichier hébergé à l’adresse : http://james.ccpower.ru/dima.exe, le fichier est donc enregistrer sous le nom de la string précédemment généré dans le répertoire courant.
(Par faute de temps je n’ai pas analysé cette exécutable, si une personne l’a déjà fait, qu’il me fasse signe merci.)
Une fois le fichier écrit, on l’exécute bien évidemment.
A présent, on aperçoit plusieurs apis/fonctions permettant de formater des chaînes de caractères.
Tout d’abord, on formate une chaîne du genre : « C:\\services.exe:*:Enabled:Flash Player2 » ..
Mais pourquoi?!
Juste en dessous, on crée une clé dans la base de registre Windows, a cette emplacement : « HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\ » sous le nom de FlashPlayer2..le petit vilain : ).



On a bien compris, cette clé va permettre d’assurer l’exécution de l’exécutable lors des redémarrages de l’ordinateur.
Une autre clé de créer, cette fois ci c’est ici : « HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\SharedAccess\\
Parameters\\FirewallPolicy\\StandardProfile\\AuthorizedApplications\\List\\
» avec pour nom le path vers l’exécutable, et pour valeur le full path concaténé avec « :*:Enabled:Flash Player2 » (d’où notre formatage de chaîne de caractère précédemment).
Cette clé va permettre d’autoriser les connections de services.exe, le firewall Windows ne viendra donc pas afficher de message d‘alerte par exemple.
Mais, une question devrait vous venir à l’esprit : le « :*:Enabled:Flash Player2 », que signifie t-il?
Hum apparemment, c’est histoire de tromper l’utilisateur.
Allez donc voir dans le panneau de configuration, dans les propriétés du firewall de Windows, dans les exceptions.. Que voit-on? Flash Player2 : ).



A présent, la dernier clé ajouté à l’emplacement : « HKEY_CLASSES_ROOT\\.htc ».
On y créer une clé qui se prénomme : Content Type avec la valeur ryan1918.com.
Bon, cette fois ci c’est plutôt explicite, on change le mime type des fichiers .htc.




Nous continuons, jusqu’à tomber sur une routine de décryptage de chaîne de caractères, on y trouve des messages en toutes langues du genre : « c'est pas toi?!! » ou « emoticon with your face ».
Ces messages correspondraient normalement a ceux envoyé par MSN afin d’assurer la propagation du ver.
Nous arrivons à la fin, le plus juteux sûrement, une socket!
En analysant un peu les routines, on constate que c’est enfaite une connection sur un serveur irc (asl.aldanma.net) sur le port tcp 7575.
Cependant, le malware prend le soin de récupérer des informations sur lequel il est lancé, comme la langue utilisé (par le biais de GetLocaleInfo).
Ensuite on formate une chaîne de caractères qui nous servira de pseudo sur le serveur, une chaîne du style : « [FRA-0H-avwooezrf ».
C’est ici que la première partie de cet article s’arrête : ).
J’ai décidé de traiter le dernier call, le plus intéressant et le plus long à analyser, la semaine prochain donc, cela vous laisse le temps de mener votre petit enquête vous aussi.

Mais normalement.. Une question subsiste.
Lors de l’injection de code dans l’explorer au début de notre malware, comment peut-on bien faire pour debugguer la routine lancée par le thread?
Je vais vous filer une petite astuce.

Tout d’abord, créer vous un programme bidon, une messagebox tout simplement.
Nous allons l’ouvrir avec Olly, lancer le prog, et donc ne pas valider la messagebox, de sorte que le processus reste en debug.
Ensuite, nous ouvrons notre malware sous Olly.
Nous arrivons a l’OpenProcess(), nous allons alors modifié le PID du processus sur lequel on va créer le remote thread, de sorte a pouvoir le debugguer.
On modifie donc le registre qui va être pusher pour l’appel a OpenProcess.
Nous allons donc ouvrir notre processus ’bidon’, notre messagebox.
Ensuite au moment du VirtualAllocEx, nous récupérons dans eax l’adresse sur laquelle on a écrit les données.

On retourne du côté de notre messagebox sous Olly, et on s’en va rechercher cette adresse justement.
« No Memory Address », bien évidemment Olly n’est pas au courant que nous avons allouer de la mémoire dans le processus (VirtualAllocExec), on va donc dans view, puis Memory.
Nous recherchons donc notre adresse, et là magique ça fonctionne!
A présent nous posons un break point sur la routine, et nous allons lancer le CreateRemoteThread à partir du Olly qui debug notre malware.
Et BIM ça break!

Voilà une petite astuce permettant de pouvoir tracer une routine créer dans un autre processus.

Ce petit article, est donc terminé, en espérant avoir été clair, et vous avoir apporter quelque chose.
Cette analyse, m'aura beaucoup apporter, que ce soit au niveau de la manipulation d'outil tel que OllyDbg et IDA, mais aussi sur le plan de la compréhension par le biais de dump asm.
N'hésiter donc pas, à analyser un binaire, que ce soit un malware ou pas, on y trouve souvent des petites techniques intéréssantes au niveau coding.

Je vous file un petit code permettant de décrypter des chaînes qui sont xorer avec une certaine clé ainsi qu‘un petit pack contenant les binaires et les .idbs (faites en bonne usage):
-Dexor.c.
-Pack_Analyse_Naked.com.rar.

Cya.

PS : Merci à Baboon!