Un développeur qui écrire du code dans un programme normal en C ou C++ via Visual Studio peut utiliser les fonctions de la DLL
kernel32.dll avec les Api LoadLibraryA
(..) et GetProcAddress(..)
pour
charger des DLLs arbitraire et récupérer les pointeurs de fonctions exportées de la DLL.
Les Auteurs de shellcode sont souvent confrontés à des
contraintes de taille, donc y compris la chaîne complète de chaque fonction de
l'API qu'il souhaite utiliser pourrait être prohibitif.
Plutôt que d'utiliser la chaîne complète, une méthode
efficace pour réduire la taille est de pré-calcul les hashs numériques des noms de
fonctions et d'inclure ces valeurs dans le shellcode.
Cela implique de modifie le processus de résolution d'importation dans le shellcode.
Comme le shellcode ne peuvent plus compter sur
Comme le shellcode ne peuvent plus compter sur
GetProcAddress
pour récupérer les pointeurs de fonction. Au contraire, il devra analyser les fichiers DLL et le PE
en mémoire pour trouver le répertoire d'exportation et de parcourir son éventail table des fonctions exporté. Pour
chaque nom de fonction d'exportation, le shellcode calcule le hachage et la
compare la valeur intrinsèque dans le shellcode. La fonction API correspondante a été trouvée lorsque les
valeurs correspondent.
Cela peut sembler difficile de retrouver qu'elle hash correspond à qu'elle fonction API.Mais heureusement, la plupart des auteurs shellcode réutiliser des algorithmes
et des valeurs de hachage connues, ce qui rend l'analyse de l'inverse l'ingénierie
beaucoup plus simple. La fonction de hachage
la plus commun que nous avons vu dans les échantillons de shellcode récupéré est
inclus sur Metasploit est l'algorithme
ROR13(Additive+1) ou ROR13(Additive).
Le
hachage est en aucune façon une forte de hachage cryptographique, mais il
accomplit le but de calculer une valeur entière basée sur une chaîne d'entrée
de longueur arbitraire. La seule
contrainte réelle sur l'algorithme de hachage est que chaque fonction de l'API
que le développeur souhaite utiliser dans une DLL doit avoir une valeur de hachage
unique, et ce simple calcul ROR-13 est très efficace. Des hashs insolites que nous avons rencontré sont généralement
de légère variante de cette idée: ils peuvent soit tourner d'une valeur différente,ou
tournent à gauche plutôt que à droite, ou d'utiliser d'autres opérateurs de
mélanger sur les caractères de la chaîne d'entrée pour former un résultat entier.
Maintenant
soyons réaliste le Ror13(Additive) ou Ror13(Additive+1) n'est plus celui qui est le plus utiliser dans
les malwares depuis bien longtemps ( celle-ci est utiliser surtout pour
apprendre et initialisation des jeunes à cette technique).
nous
allons voir dans la suite des hashs ayant plus d'intérêt et qui on une plus forte utilisation dans les
malwares.
le Hash
composite qui sont une évolution naturelle du Hash de fonction vu au dessus.
Le
développeur de shellcode à besoin plus souvent d'un couplé ( Module + Function
)
de ce
principe est née la composition qui est la comme de 2 Hashs celui du
module additionner à celui du hash de
la fonction qui sont nommé soit
Composite ou Hybride
Hach(Module+ Function) = Hash(Module) by (AlgoHashX) +
Hash(Function) by (AlgoHashY)
II. Introduction
Nous pouvons les caractérisés par la formule
suivant:
Hach(Module+ Function) = Hash(Module) by (AlgoHashX) +
Hash(Function) by (AlgoHashY)
En générale, il utilise
AlgoHashX = AlgoHashY pour des raisons de simplicité du code dans les malwares.
mais cela va duré qu'un temps des variants sont déjà visible sur différents sources.
de ce fait vous pouvez vous douté qu'il existe une
infinité de variante possible est qui n'est pas simple de déterminer
l'algorithme que l'auteur d'un malware a utilisé.
Cela peut sembler difficile,
mais heureusement, la plupart des auteurs shellcode réutiliser des algorithmes
composite et des valeurs de hachage connues.
Pourquoi, cela s'explique par le
fait qu'il utilise souvent des codes qu'ils ont développé et cela dans des
Rootkits perso ou même utilise des codes d'autre.
Voici certains hashes largement utilisés
qui sont tous de tirer de l'algorithme Hash
Hybride
"Algo
Hash Hybride : ( HashRor13Additive+1)Unicode Upper + (HashRor13Additive+1)Ansi"
Nous les avons regroupés par Module pour vous permettre de mieux les retrouvés
0x006B8029
|
"ws2_32.dll! WSAStartup"
|
0xE0DF0FEA
|
"ws2_32.dll! WSASocketA"
|
0x6737DBC2
|
"ws2_32.dll! Bind"
|
0xFF38E9B7
|
"ws2_32.dll!listen"
|
0xE13BEC74
|
"ws2_32.dll!accept"
|
0x614D6E75
|
"ws2_32.dll! Closesocket"
|
0x6174A599
|
"ws2_32.dll! Connect"
|
0x5FC8D902
|
"ws2_32.dll! Recv"
|
0x5F38EBC2
|
"Ws2_32.dll! Send"
|
0x5BAE572D
|
"kernel32.dll! WriteFile"
|
0x4FDAF6DA
|
"kernel32.dll! CreateFileA"
|
0x13DD2ED7
|
"kernel32.dll! DeleteFileA"
|
0xE449F330
|
"kernel32.dll! GetTempPathA"
|
0x528796C6
|
"kernel32.dll! CloseHandle"
|
0x863FCC79
|
"kernel32.dll! CreateProcessA"
|
0xE553A458
|
"kernel32.dll! VirtualAlloc"
|
0x300F2F0B
|
"kernel32.dll! VirtualFree"
|
0x0726774C
|
"kernel32.dll! LoadLibraryA"
|
0x7802F749
|
"kernel32.dll! GetProcAddress"
|
0x601D8708
|
"kernel32.dll! WaitForSingleObject"
|
0x876F8B31
|
"kernel32.dll! WinExec"
|
0x9DBD95A6
|
"kernel32.dll! GetVersion"
|
0xEA320EFE
|
"kernel32.dll! SetUnhandledExceptionFilter"
|
0x56A2B5F0
|
"kernel32.dll! ExitProcess"
|
0x0A2A1DE0
|
"kernel32.dll! ExitThread"
|
0x6F721347
|
"ntdll.dll! RtlExitUserThread"
|
0x23E38427
|
"advapi32.dll! RevertToSelf"
|
Nous avons développer un outil permettant de visualisé l'algorithme utilisé pour les cas cité au dessus :
Pour l'exemple nous allons effectué le calcule du Hash Hybride de "kernel32.dll!GetTempPathA" qui va nous donnée 0xE449F330
I. Petit POC via un exemple de ShellCode
Nous allons voir un petit shellcode utilisant un
hash composite. Ce shellcode ne fera que un simple WinExec("notepad.exe")
Nous avons besoin que le shellcode
utilise l'Api "WinExec" contenu dans Kernel32.dll. Nous utiliserons
un hash avec l'algorithme présenté au dessus.
"(
HashRor13Additive+1)Unicode Upper + (HashRor13Additive+1)Ansi"
Pour ce faire, nous allons utiliser un petit outil qui
calcule est Hash. Cela pour vous permettre de bien comprendre le Hash .
Unitairement le hash du module est 0x92AF16DA et comme il est Unicode Upper.
Cela signifie que quelque soit l'écriture majuscule ou minuscule de "kernel32.dll".
Vous aurez toujours la même valeur. Ce que vous pouvez visualiser sur l'outil
"Kernel32.Dll"
=> 0x92AF16DA
"KeRNeL32.DLl"
=> 0x92AF16DA
le Hash de "WinExec" en ROR13AdditivePlus1Ansi est
0xF4C07457
de ce fait, il est simple de construire le hash du couple
(Kernel32.dll , WinExec )
0x92AF16DA
+ 0x92AF16DA = 0x876F8B31
Voici notre petit shellcode basique pour monter
l'utilisation du Hash Hybride 0x876F8B31
\x55\x8B\xEC\x55\xE8\x89\x00\x00\x00\x60\x89\xE5\x31\xD2\x64\x8B
\x52\x30\x8B\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F\xB7\x4A\x26\x31
\xFF\x31\xC0\xAC\x3C\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2
\xF0\x52\x57\x8B\x52\x10\x8B\x42\x3C\x01\xD0\x8B\x40\x78\x85\xC0
\x74\x4A\x01\xD0\x50\x8B\x48\x18\x8B\x58\x20\x01\xD3\xE3\x3C\x49
\x8B\x34\x8B\x01\xD6\x31\xFF\x31\xC0\xAC\xC1\xCF\x0D\x01\xC7\x38
\xE0\x75\xF4\x03\x7D\xF8\x3B\x7D\x24\x75\xE2\x58\x8B\x58\x24\x01
\xD3\x66\x8B\x0C\x4B\x8B\x58\x1C\x01\xD3\x8B\x04\x8B\x01\xD0\x89
\x44\x24\x24\x5B\x5B\x61\x59\x5A\x51\xFF\xE0\x58\x5F\x5A\x8B\x12
\xEB\x86\x5D\x68\x01\x00\x00\x00\xE8\x0C\x00\x00\x00\x6E\x6F\x74
\x65\x70\x61\x64\x2E\x65\x78\x65\x00\x68\x31\x8B\x6F\x87\xFF\xD5
\x5D\x8B\xE5\x5D\xC3
|
Pour ce qui ne sont familiariser avec les Shellcodes ( en OpCode ), nous allons vous le transcrire en code Asm X86 via un outil d'analyse perso qui redonne le code assembleur du shellcode quelconque " EzShellCodeAnalyzerX32.exe"
Cela donne en code Assembleur X32
voici le listing que nous allons étudier dans notre
exemple
00000000: 55 PUSH
EBP
00000001: 8B EC MOV
EBP,ESP
00000003: 55 PUSH
EBP
00000004: E8 89 00 00 00 CALL 00000089h (+89h ->:00000092)
00000009: 60 PUSHAD
0000000A: 89 E5 MOV
EBP,ESP
0000000C: 31 D2 XOR
EDX,EDX
0000000E: 64 8B 52 30 MOV EDX,DWORD PTR FS:[EDX+30h]
00000012: 8B 52 0C MOV
EDX,DWORD PTR DS:[EDX+0Ch]
00000015: 8B 52 14 MOV
EDX,DWORD PTR DS:[EDX+14h]
00000018: 8B 72 28 MOV
ESI,DWORD PTR DS:[EDX+28h]
0000001B: 0F B7 4A 26 MOVZX ECX,WORD PTR [EDX+26h]
0000001F: 31 FF XOR
EDI,EDI
00000021: 31 C0 XOR
EAX,EAX
00000023: AC LODSB
00000024: 3C 61 CMP
AL,61h
00000026: 7C 02 JL
02h (rel8)(+02h ->:0000002A)
00000028: 2C 20 SUB
AL,20h
0000002A: C1 CF 0D ROR
EDI,0Dh (13)
0000002D: 01 C7 ADD
EDI,EAX
0000002F: E2 F0 LOOP F0h
(-FFFFFFF0h=>:00000021)Dec ECX or CX jmp if !=0
00000031: 52 PUSH
EDX
00000032: 57 PUSH
EDI
00000033: 8B 52 10 MOV
EDX,DWORD PTR DS:[EDX+10h]
00000036: 8B 42 3C MOV
EAX,DWORD PTR [EDX+3Ch]
00000039: 01 D0 ADD
EAX,EDX
0000003B: 8B 40 78 MOV
EAX,[EAX+78h]
0000003E: 85 C0 TEST
EAX,EAX
00000040: 74 4A JZ
4Ah (-FFFFFFB6h ->:0000008C)
00000042: 01 D0 ADD
EAX,EDX
00000044: 50 PUSH
EAX
00000045: 8B 48 18 MOV
ECX,DWORD PTR[EAX+18h]
00000048: 8B 58 20 MOV
EBX,DWORD PTR DS:[EAX+20h]
0000004B: 01 D3 ADD
EBX,EDX
0000004D: E3 3C JECXZ
3Ch (-FFFFFFC4h ->:0000008B)
0000004F: 49 DEC
ECX
00000050: 8B 34 8B MOV
ESI,[EBX+ECX*4]
00000053: 01 D6 ADD
ESI,EDX
00000055: 31 FF XOR
EDI,EDI
00000057: 31 C0 XOR
EAX,EAX
00000059: AC LODSB
0000005A: C1 CF 0D ROR
EDI,0Dh (13)
0000005D: 01 C7 ADD
EDI,EAX
0000005F: 38 E0 CMP
AL,AH
00000061: 75 F4 JNZ
F4h (rel8)(-0Ch ->:00000057)
00000063: 03 7D F8 ADD
EDI,DWORD PTR [EBP-08h]
00000066: 3B 7D 24 CMP
EDI,DWORD PTR [EBP+24h]
00000069: 75 E2 JNZ
E2h (rel8)(-1Eh ->:0000004D)
0000006B: 58 POP
EAX
0000006C: 8B 58 24 MOV
EBX,DWORD PTR DS:[EAX+24h]
0000006F: 01 D3 ADD
EBX,EDX
00000071: 66 8B 0C 4B MOV CX,WORD PTR DS:[EBX+ECX*2]
00000075: 8B 58 1C MOV
EBX,DWORD PTR DS:[EAX+1Ch]
00000078: 01 D3 ADD
EBX,EDX
0000007A: 8B 04 8B MOV
EAX,[EBX+ECX*4]
0000007D: 01 D0 ADD
EAX,EDX
0000007F: 89 44 24 24 MOV DWORD PTR[ESP+24h],EAX
00000083: 5B POP
EBX
00000084: 5B POP
EBX
00000085: 61 POPAD
00000086: 59 POP
ECX
00000087: 5A POP
EDX
00000088: 51 PUSH
ECX
00000089: FF E0 CALL
EAX
0000008B: 58 POP
EAX
0000008C: 5F POP
EDI
0000008D: 5A POP
EDX
0000008E: 8B 12 MOV
EDX,DWORD PTR [EDX]
00000090: EB 86 JMP
86h (-7Ah ->:00000018)
00000092: 5D POP
EBP
00000093: 68 01 00 00 00 PUSH 00000001h ""
00000098: E8 0C 00 00 00 CALL 0000000Ch (+0Ch ->:000000A9)
db
"notepad.exe"
0000009D: 6E 6F 74 65 70 61 64 2E 65 78 65 00
000000A9: 68 31 8B 6F 87 PUSH 876F8B31h "1‹o‡"
(876F8B31=Hash[Ror13-Hybrid](Kernel32.dll!WinExec)
000000AE: FF D5 CALL
EBP
000000B0: 5D POP
EBP
000000B1: 8B E5 MOV
ESP,EBP
000000B3: 5D POP
EBP
000000B4: C3 RET
|
Nous allons simplifier la compréhension du shellcode,
l'outil dispose de signature de fonction basique présent dans le shellcode.
Cela permet de donner une le lecture plus simple et débuter l'analyse de
ShellCode sans détaille technique. Cela avez crée pour détecter les souches de
code utiliser entre différents shellcode disponible sur le Net.
Aucun commentaire:
Enregistrer un commentaire