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";
|
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)
|
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.
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.
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.
- dans leur ordre de mise en mémoire (InLoadOrderModuleList),
- dans leur ordre d'initialisation (InInitializationOrderModuleList).
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 :
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
|
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
Ce commentaire a été supprimé par un administrateur du blog.
RépondreSupprimer