dimanche 26 mars 2017

ShellCode - GetProcAddressByHashROR13Additive(..)


 les Hashs ROR13Additive dans les shellcodes

Nous allons présenté les notions de base sur les shellcodes et l'indépendance à la version de windows



Pour créer un shellcode indépendant de la version windows ( XP à W8 ) mais sur le même socle X86 ou X64 . Les techniques sont souvent baser sur les même approche , nous devons d'abord obtenir l'adresse de base de kernel32.dll, puis nous devons obtenir l'adresse des fonctions LoadLibraryA et GetProcAddress.
Avec cette information nous pouvons obtenir l'adresse de n'importe quelle fonction et nous pouvons créer un shellcode indépendant de la version Windows.

Pour avoir le HMODULE de "Kernel32.dll" ou pour ce qui préfère l'adresse de base du module kernel32.dll en mémoire pour le processus , il y a au moins 3 méthodes connu depuis longtemps qui tourne au tour des 3 composantes essentielle d'un processus le TEB , PEB et SEH permettant point de référence commun quelque soit le processus windows.

Le TEB (auparavant appelé Thread Information Block) est une structure, placée en mémoire user land. elle décrit un thread. Bien sûr si vous avez un processus avec 3 Threads, il y aura 3 TEB pour chacun des threads de votre processus.
 
Le PEB quand à lui est une structure, placée en mémoire user land, qui décrit le processus.

Il faut comprendre que sous Windows un processus n’exécute rien, il n’est qu'une représentation un espace mémoire organisé dans lequel le code est exécuter par un Thread principal, ainsi un processus a au mimimun un Thread dit primaire qui peut engendrer de nouveau Threads qui occuperont ce même espace mémoire délimité par cette notion de processus et exécuterons leur propre code. Pour que l'opération de « multi-thread » soit possible alors que le processeur ne peut que réaliser une instruction en même temps, chaque Thread à son propre CONTEXT c’est à dire que pour chaque Thread qui n’est pas en train d’être exécuter le processeur a sauvegardé dans cette structure CONTEXT tout les états des registres processeurs au moment de passer à un autre. Ainsi pour « switcher » de Threads en Threads il recharge à chaque fois le CONTEXT exécutant ensuite quelques instructions puis sauvegarde le CONTEXT et peut alors passer au suivant.



Il y une relation entre les TEB et PEB, simplement tous thread est rattaché à un processus et doit connaître sont processus. c'est pour quoi dans la struture du TEB a un pointeur sur le PEB 

Donc pour beaucoup de shellcode sous Windows, vous trouverez deux fonctions que l'on nommera  GetKernel32 permettant d'obtenir le HMODULE en mémoire de Kernel32.dll et une fonction GetProcAddressByHash permettant d'avoir l'équivalent de la fonction microsoft "GetProcAddressA(..)"

Vous trouverez des variants qui en une seul fonction combine les deux fonctions que l'on nommera au dessus que l'on nommera CallApi que l'on vera dans un second temps .
 
Pour illustre, nous avons prendre un shellcode X du Net qui apparaît sur plusieurs sites
qui sont baser sur la même principe


Pour en trouver d'autre, il vous suffit de faire une recherche sur Google avec l'empreinte

\x60\x8B\x6C\x24\x24\x8B\x45\x3C\x8B\x54\x28\x78

ou

0x60,0x8b,0x6c,0x24,0x24,0x8b,0x45,0x3C,0x8b,0x54,0x28,0x78

Voici celui le shellcode que l'on va étudier, montrant le concept des 2 fonctions GetKernel et GetProcAddressByHash


unsigned char  SN67_Shellcode_DllInjection1[] =
"\xd9\xeb\x9b\xd9\x74\x24\xf4\x31\xd2\xb2"
"\x77\x31\xc9\x64\x8b\x71\x30\x8b\x76\x0c"
"\x8b\x76\x1c\x8b\x46\x08\x8b\x7e\x20\x8b"
"\x36\x38\x4f\x18\x75\xf3\x59\x01\xd1\xff"
"\xe1\x60\x8b\x6c\x24\x24\x8b\x45\x3c\x8b"
"\x54\x28\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\xb2"
"\x08\x29\xd4\x89\xe5\x89\xc2\x68\x8e\x4e"
"\x0e\xec\x52\xe8\x9f\xff\xff\xff\x89\x45"
"\x04\xbb\x7e\xd8\xe2\x73\x87\x1C\x24\x52"
"\xe8\x8e\xff\xff\xff\x89\x45\x08\x68\x6c"
"\x6c\x20\x41\x68\x33\x32\x2e\x64\x68\x75"
"\x73\x65\x72\x88\x5c\x24\x0a\x89\xe6\x56"
"\xff\x55\x04\x89\xc2\x50_xbb\xa8\xa2\x4d"
"\xbc\x87\x1c\x24\x52\xe8\x61\xff\xff\xff"
"\x68\x6f\x78\x58\x20\x68\x61\x67\x65\x42"
"\x68\x4d\x65\x73\x73\x31\xdb\x88\x5c\x24"
"\x0a\x89\xe3\x68\x58\x20\x20\x20\x68\x4d"
"\x53\x46\x21\x68\x72\x6f\x6d\x20\x68\x6f"
"\x2c\x20\x66\x68\x48\x65\x6c\x6c\x31\xc9"
"\x88\x4c\x24\x10\x89\xe1\x31\xd2\x52\x53"
"x51\x52\xff\xd0\x31\xc0\x50\xff\x55\x08";

Nous allons décoder ce shellcode et obtenir le code Assembleur via un de nos outils d'analyse



Pour ce qui voudrait le faire pour d'autre shellcode, vous pouvez utiliser les d'assembleur en ligne comme qui vous donnerons la même chose à la différence des décodage des hashs et string ou des empreintes de code de fonction


Voici le listing du shellcode


00000000:   D9 EB                                FLDPI ;met la constante Pi dans le registre ST(0)
00000002:   9B                                      WAIT
00000003:   D9 74 24 F4                      FNSTENV [ESP-0Ch]
00000007:   31 D2                                 XOR EDX,EDX
00000009:   B2 77                                 MOV DL,77h
0000000B:   31 C9                                XOR ECX,ECX
0000000D:   64 8B 71 30                      MOV ESI,DWORD PTR FS:[ECX+30h]
00000011:   8B 76 0C                           MOV ESI,[ESI+0Ch]
00000014:   8B 76 1C                           MOV ESI,[ESI+1Ch]
00000017:   8B 46 08                            MOV EAX,DWORD PTR[ESI+08h]
0000001A:   8B 7E 20                           MOV EDI,[ESI+20h]
0000001D:   8B 36                                MOV ESI,[ESI]
0000001F:   38 4F 18                            CMP BYTE PTR[EDI+18h],CL
00000022:   75 F3                                 JNZ F3h (rel8)(-0Dh ->:00000017)
00000024:   59                                       POP ECX
00000025:   01 D1                                 ADD ECX,EDX
00000027:   FF E1                                 JMP ECX
00000029:   60                                       PUSHAD
0000002A:   8B 6C 24 24                     MOV EBP,[ESP+24h]
0000002E:   8B 45 3C                           MOV EAX,DWORD PTR [EBP+3Ch]
00000031:   8B 54 28 78                       MOV EDX,DWORD PTR[EBP+EAX+78h]
00000035:   01 EA                                ADD EDX,EBP
00000037:   8B 4A 18                           MOV ECX,[EDX+18h]
0000003A:   8B 5A 20                          MOV EBX,DWORD PTR [EDX+20h]
0000003D:   01 EB                                ADD EBX,EBP
0000003F:   E3 34                                 JECXZ 34h (-FFFFFFCCh ->:00000075)
00000041:   49                                       DEC ECX
00000042:   8B 34 8B                           MOV ESI,[EBX+ECX*4]
00000045:   01 EE                                 ADD ESI,EBP
00000047:   31 FF                                 XOR EDI,EDI
00000049:   31 C0                                 XOR EAX,EAX
0000004B:   FC                                     CLD
0000004C:   AC                                    LODSB
0000004D:   84 C0                                TEST AL,AL
0000004F:   74 07                                 JZ 07h (-FFFFFFF9h ->:00000058)
00000051:   C1 CF 0D                          ROR EDI,0Dh (13)
00000054:   01 C7                                 ADD EDI,EAX
00000056:   EB F4                                JMP F4h (-0Ch ->:0000004C)
00000058:   3B 7C 24 28                      CMP EDI,[ESP+28h]
0000005C:   75 E1                                 JNZ E1h (rel8)(-1Fh ->:0000003F)
0000005E:   8B 5A 24                           MOV EBX,DWORD PTR [EDX+24h]
00000061:   01 EB                                 ADD EBX,EBP
00000063:   66 8B 0C 4B                      MOV CX,WORD PTR DS:[EBX+ECX*2]
00000067:   8B 5A 1C                          MOV EBX,DWORD PTR [EDX+1Ch]
0000006A:   01 EB                                 ADD EBX,EBP
0000006C:   8B 04 8B                           MOV EAX,[EBX+ECX*4]
0000006F:   01 E8                                 ADD EAX,EBP
00000071:   89 44 24 1C                       MOV DWORD PTR[ESP+1Ch],EAX
00000075:   61                                       POPAD
00000076:   C3                                      RET
00000077:   B2 08                                 MOV DL,08h
00000079:   29 D4                                 SUB ESP,EDX
0000007B:   89 E5                                 MOV EBP,ESP
0000007D:   89 C2                                MOV EDX,EAX
0000007F:   68 8E 4E 0E EC                PUSH EC0E4E8Eh  (EC0E4E8E=Hash[ROR13(Additive)]('LoadLibraryA'))
00000084:   52                                       PUSH EDX
00000085:   E8 9F FF FF FF                CALL FFFFFF9Fh (-61h ->:00000029)
0000008A:   89 45 04                            MOV DWORD PTR[EBP+04h],EAX
0000008D:   BB 7E D8 E2 73               MOV EBX,73E2D87Eh  (73E2D87E=Hash[ROR13(Additive)]('ExitProcess'))
00000092:   87 1C 24                            XCHG EBX,DWORD PTR[ESP]
00000095:   52                                       PUSH EDX
00000096:   E8 8E FF FF FF                 CALL FFFFFF8Eh (-72h ->:00000029)
0000009B:   89 45 08                            MOV DWORD PTR[EBP+08h],EAX
0000009E:   68 6C 6C 20 41                 PUSH 41206C6Ch "ll A"
000000A3:   68 33 32 2E 64                 PUSH 642E3233h "32.d"
000000A8:   68 75 73 65 72                  PUSH 72657375h "user"
000000AD:   88 5C 24 0A                    MOV [ESP+0Ah],BL  
000000B1:   89 E6                                 MOV ESI,ESP
000000B3:   56                                      PUSH ESI
000000B4:   FF 55 04                           CALL DWORD PTR [EBP+04h]
000000B7:   89 C2                                MOV EDX,EAX
000000B9:   50                                      PUSH EAX
000000BA:   5F                                     POP EDI
000000BB:   78 62                                JS 62h (rel8)(+62h ->:0000011F)'Saut si drapeau de signe vaut 1 (SF=1)'
000000BD:   62 A8 A2 4D BC 87        BOUND EBP,DWORD PTR [EAX-7843B25Eh]
000000C3:   1C 24                                SBB AL,24h
000000C5:   52                                      PUSH EDX
000000C6:   E8 61 FF FF FF                CALL FFFFFF61h (-9Fh ->:0000002C)
000000CB:   68 6F 78 58 20                 PUSH 2058786Fh "oxX "
000000D0:   68 61 67 65 42                  PUSH 42656761h "ageB"
000000D5:   68 4D 65 73 73                 PUSH 7373654Dh "Mess"
000000DA:   31 DB                              XOR EBX,EBX
000000DC:   88 5C 24 0A                    MOV [ESP+0Ah],BL  
000000E0:   89 E3                                 MOV EBX,ESP
000000E2:   68 58 20 20 20                  PUSH 20202058h "X   "
000000E7:   68 4D 53 46 21                 PUSH 2146534Dh "MSF!"
000000EC:   68 72 6F 6D 20                PUSH 206D6F72h "rom "
000000F1:   68 6F 2C 20 66                 PUSH 66202C6Fh "o, f"
000000F6:   68 48 65 6C 6C                 PUSH 6C6C6548h "Hell"
000000FB:   31 C9                                XOR ECX,ECX
000000FD:   88 4C 24 10                      MOV BYTE PTR SS:[ESP+10h],CL 
00000101:   89 E1                                 MOV ECX,ESP
00000103:   31 D2                                 XOR EDX,EDX
00000105:   52                                       PUSH EDX
00000106:   53                                       PUSH EBX
00000107:   78 35                                  JS 35h (rel8)(+35h ->:0000013E)'Saut si drapeau de signe vaut 1 (SF=1)'
00000109:   31 52 FF                            XOR DWORD PTR [EDX-01h],EDX
0000010C:   D0                                     (BAD / CODE)
0000010D:   31 C0                                XOR EAX,EAX
0000010F:   50                                      PUSH EAX
00000110:   FF 55 08                            CALL DWORD PTR [EBP+08h]


Comme cela vous ne trouver toujours pas grand chose de changer et pourtant, déjà ce shellcode utilise des hash ROR13 additive qui sous entend qu'il y a une méthode pour trouver les addresses des fonctions via le Hash

EC0E4E8E=Hash[ROR13(Additive)]('LoadLibraryA'))
73E2D87E=Hash[ROR13(Additive)]('ExitProcess'))

De plus si vous regarder bien les lignes suivante, ce code n'est pas anodin

0000000B:   31 C9                      XOR ECX,ECX
0000000D:   64 8B 71 30              MOV ESI,DWORD PTR FS:[ECX+30h]
00000011:   8B 76 0C                  MOV ESI,[ESI+0Ch]
00000014:   8B 76 1C                  MOV ESI,[ESI+1Ch]
00000017:   8B 46 08                  MOV EAX,DWORD PTR[ESI+08h]
0000001A:   8B 7E 20                  MOV EDI,[ESI+20h]
0000001D:   8B 36                      MOV ESI,[ESI]
0000001F:   38 4F 18                  CMP BYTE PTR[EDI+18h],CL
00000022:   75 F3                      JNZ F3h (rel8)(-0Dh ->:00000017)

On va expliquer cela plus en détaille, nous vous parlions de la fonction GetKernel32


Il existe une multitude de variante de la fonction GetKernel32, mais elle fonctionne quasiment toutes sur le même principe


Accès au point d'entrer du TEB via le registre FS, dela récupération du pointeur sur le PEB  et du PEB atteindre PEB_LDR_DATA
Contenant la listes des DLLs du processus qui est plusieurs liste chaînés en général on utilise celle de "InMemoryOrderModuleList"
On la parcours jusqu'a trovuer le Module "Kernel32.dll" est obtenir sont HMODULE.

Nous vous avons modéliser cette séquence via un schéma qui peut être utiliser en C ou C++
relation entre les structures TEB PEB PEB_LDR_DATA en mémoire pour un processus

Pour bien comprend la mécanique, nous vous avons associé les instructions Asm avec le TEB et PEB
Cela vous rendra le code plus simple à modéliser











Vous allez me dire oui mais des dlls nommée BadName.dll  va être vu comme bonne. Hors ce ne sera pas  kernel32.dll. Exacte, mais il y a autre chose qui faut prendre en considération c'est que le l'ordre des DLLs n'est pas fixer au hasard

Quelques explications s'imposent. Car il y a une logique à comprendre dans le chargement des DLL sous Windows.

D'une part le loader Windows charge systématiquement dans l'ordre, les modules ntdll.dll et puis kernel32.dl.
D'autre part il crée une liste des modules dans l'ordre de leur initialisation. Dans ce cas, kernel32.dll sera dans les premiers module initialisé et donc une autre Dll même ayant un nom de 11 caractères sera à prêt dans la liste.
Vous trouverez d'autre variant de la fonction GetKernel32 qui utilise l'une des autres listes chaîné
- dans leur ordre de mise en mémoire (InLoadOrderModuleList),
- dans leur ordre d'initialisation (InInitializationOrderModuleList).

Si nous écrivons la fonction GetKernel32 du shellcode dans un Visual Studio, cela donnera cela



HMODULE __declspec(naked)AsmGetKernel32_V10()
{
    //K  E  R  N  E  L  3  2  .  D  L  L  \00
    //0  1  2  3  4  5  6  7  8  9  10 11 12
    __asm
                {
                     PUSH ESI
                     PUSH EDI

                     XOR ECX,ECX                                        // ecx =0x00000000
                     MOV ESI,DWORD PTR FS:[ECX+30h]    // esi = Get &(PEB) (FS:[0x30])
                     MOV ESI,DWORD PTR [ESI+0Ch]           // esi = PEB->Ldr (PEB_LDR_DATA)
                     MOV ESI,DWORD PTR [ESI+1Ch]           // esi = PEB->Ldr.InInitOrder (InMemoryModuleList)
next_module:         
                     MOV EAX,DWORD PTR[ESI+08h]          // eax = InMemOrder[X].base_address
                     MOV EDI,DWORD PTR[ESI+20h]            // edi = InMemOrder[X].module_name (unicode).
                     MOV ESI,[ESI]                                        // esi = InMemOrder[X].flink (module suivant).
                     CMP BYTE PTR[EDI+18h],CL                 // Uncode string 12*2=24 en hex 0x18 compare à '\0' (ECX=0/CL=0)
                     JNZ next_module                                  // Non c'est pas kernel32 => essayons le module suivant.
               
                      POP EDI
                      POP ESI

                      RET
                }
}


Nous avons un outil intégrant les différents variantes de la fonction GetKernel32. Nous vous mettons le résultat obtenu pour celle-ci décrite au dessus



























Maintenant que l'on sait ou est effectué la détermination de GetKernel32 dont la HMODULE est mis dans EAX à la sortie du bloc
Regardons d'un peu plus prêt les instruction avant et après le bloc

00000000:   D9 EB                                               FLDPI ;met la constante Pi dans le registre ST(0)
00000002:   9B                                      WAIT
00000003:   D9 74 24 F4                      FNSTENV [ESP-0Ch]
00000007:   31 D2                                XOR EDX,EDX
00000009:   B2 77                                 MOV DL,77h
...............                                                { BLOC GetKernel32 }
00000024:   59                                      POP ECX
00000025:   01 D1                                ADD ECX,EDX
00000027:   FF E1                                JMP ECX

On voit bien que hormis le Pop ECX est s'il récupérer l'adresse de départ EDX valant 77h
le ADD permet de calculer d'une adresse qui est ensuite utilisé pour le JMP
Le Shellcode suite au calcule du HMODULE de Kernel32.dll mis dans EAX va continuer sont exécution en sautant à l'addresse AddressBaseShellcode + 0x00000077

que nous avons remis en dessous

00000077:   B2 08                                 MOV DL,08h
00000079:   29 D4                                 SUB ESP,EDX
0000007B:   89 E5                                 MOV EBP,ESP
0000007D:   89 C2                                MOV EDX,EAX
0000007F:   68 8E 4E 0E EC                 PUSH EC0E4E8Eh "ŽN
ì" (EC0E4E8E=Hash[ROR13(Additive)]('LoadLibraryA'))
00000084:   52                                       PUSH EDX
00000085:   E8 9F FF FF FF                                CALL FFFFFF9Fh (-61h ->:00000029)
0000008A:   89 45 04                            MOV DWORD PTR[EBP+04h],EAX
0000008D:   BB 7E D8 E2 73               MOV EBX,73E2D87Eh "~Øâs" (73E2D87E=Hash[ROR13(Additive)]('ExitProcess'))
00000092:   87 1C 24                            XCHG EBX,DWORD PTR[ESP]
00000095:   52                                       PUSH EDX
00000096:   E8 8E FF FF FF                                CALL FFFFFF8Eh (-72h ->:00000029)
0000009B:   89 45 08                            MOV DWORD PTR[EBP+08h],EAX

Delà on voit que la fonction appelé par les deux call en rouge est de la forme
DWORD FuncX(HMODULE hMod , DWORD dwHashRor13Additive )

en regardant le bloc à l'adresse 0x00000029 et juste au Ret à l'adresse 0x00000077

On obtient le bloc suivant :


00000029:   60                                       PUSHAD
0000002A:   8B 6C 24 24                     MOV EBP,[ESP+24h]
0000002E:   8B 45 3C                           MOV EAX,DWORD PTR [EBP+3Ch]
00000031:   8B 54 28 78                       MOV EDX,DWORD PTR[EBP+EAX+78h]
00000035:   01 EA                                ADD EDX,EBP
00000037:   8B 4A 18                           MOV ECX,[EDX+18h]
0000003A:   8B 5A 20                          MOV EBX,DWORD PTR [EDX+20h]
0000003D:   01 EB                                ADD EBX,EBP
0000003F:   E3 34                                 JECXZ 34h (-FFFFFFCCh ->:00000075)
00000041:   49                                       DEC ECX
00000042:   8B 34 8B                           MOV ESI,[EBX+ECX*4]
00000045:   01 EE                                 ADD ESI,EBP
00000047:   31 FF                                 XOR EDI,EDI
00000049:   31 C0                                 XOR EAX,EAX
0000004B:   FC                                     CLD
0000004C:   AC                                    LODSB
0000004D:   84 C0                                TEST AL,AL
0000004F:   74 07                                 JZ 07h (-FFFFFFF9h ->:00000058)
00000051:   C1 CF 0D                          ROR EDI,0Dh (13)
00000054:   01 C7                                 ADD EDI,EAX
00000056:   EB F4                                JMP F4h (-0Ch ->:0000004C)
00000058:   3B 7C 24 28                      CMP EDI,[ESP+28h]
0000005C:   75 E1                                 JNZ E1h (rel8)(-1Fh ->:0000003F)
0000005E:   8B 5A 24                           MOV EBX,DWORD PTR [EDX+24h]
00000061:   01 EB                                 ADD EBX,EBP
00000063:   66 8B 0C 4B                      MOV CX,WORD PTR DS:[EBX+ECX*2]
00000067:   8B 5A 1C                          MOV EBX,DWORD PTR [EDX+1Ch]
0000006A:   01 EB                                ADD EBX,EBP
0000006C:   8B 04 8B                           MOV EAX,[EBX+ECX*4]
0000006F:   01 E8                                 ADD EAX,EBP
00000071:   89 44 24 1C                       MOV DWORD PTR[ESP+1Ch],EAX
00000075:   61                                       POPAD
00000076:   C3                                      RET


En fait celle qui nous interesse le plus la fameuse fonction GetProcAddressByHash

Shellcode Analyser extrait la fonction GetProcAddressByRor13Hash




























Nous avons un outil intégrant les différents variantes de la fonction GetProcAddressByHashRor13Additive. Nous vous mettons le résultat obtenu pour celle-ci décrite au-dessus