0% encontró este documento útil (0 votos)
18 vistas10 páginas

Funciones de kernel32.dll para Shellcodes

El documento describe cómo detectar la posición en memoria de funciones de kernel32.dll para crear shellcodes en Windows, incluyendo ejemplos de código y su traducción a hexadecimal. También se abordan las limitaciones de caracteres no imprimibles y la necesidad de generar shellcodes alfanuméricas para evitar la detección por sistemas de intrusión. Finalmente, se presenta un ejemplo de shellcode que utiliza la función Sleep y se explica cómo obtener su dirección en memoria.

Cargado por

Marsupilami
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
18 vistas10 páginas

Funciones de kernel32.dll para Shellcodes

El documento describe cómo detectar la posición en memoria de funciones de kernel32.dll para crear shellcodes en Windows, incluyendo ejemplos de código y su traducción a hexadecimal. También se abordan las limitaciones de caracteres no imprimibles y la necesidad de generar shellcodes alfanuméricas para evitar la detección por sistemas de intrusión. Finalmente, se presenta un ejemplo de shellcode que utiliza la función Sleep y se explica cómo obtener su dirección en memoria.

Cargado por

Marsupilami
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

© FUOC • PID_00208393 11 Shellcodes

Podemos usar este programa para detectar la posición en memoria de cualquier


función de [Link] que deseemos. La lista que sigue recoge algunas de
las funciones disponibles en [Link] que pueden ser de gran utilidad
a la hora de crear las shellcodes en Microsoft Windows.
CloseHandle CreateFileA
CreateProcessA CreateToolhelpSnapshot
FindClose FindFirstFileA
FindNextFileA GetComputerNameA
GetCurrentProcess GetDiskFreeSpaceA
GetDriveTypeA GetLocaleInfoA
GetPrivateProfileInt GetPrivateProfileString
GetProcessHeap GetProfileStringA
GetShortPathNameA GetSystemInfo
GetTempPathA GetUserDefaultLCID
GetVersionExA GetVolumeInformationA
GetWindowsDirectoryA HeapAlloc
HeapFree lstrcatA
Lstrcpyn lstrlenW
OpenProcess ProcessFirst
ProcessNext RtlMoveMemory
SetComputerNameA TerminateProcess
WaitForSingleObject WritePrivateProfileString
Algunas funciones disponibles en [Link]
Estas funciones son básicas en la creación de shellcodes y todas ellas están am-
pliamente documentadas en la MSDN Library de Microsoft en Internet.
Usando el programa expuesto anteriormente podemos llegar a descubrir que la
posición donde se encuentra la función Sleep es 0x777D4E86. Es importante
insistir en que este valor es único para la versión del sistema operativo sobre
la que se ha hecho la prueba y que puede cambiar entre versiones.
Salida del programa arwin
© FUOC • PID_00208393 12 Shellcodes
Sabiendo este dato y conociendo que Sleep solo toma un dato como pará-
metro para configurar los milisegundos que tiene que detener la ejecución, se
podría generar la siguiente shellcode:
xor eax,eax
mov ebx, 0x75fd4e86 ;dirección de Sleep
mov ax, 5000 ;una pausa de 5000ms
push eax
call ebx ;llamada a Sleep(ms);
Shellcode para Windows
En ese código lo primero que se realiza es, con la operación xor eax,eax, el
vaciado el registro EAX. Después se almacena en el registro EBX la dirección
de memoria de la función Sleep. En los 2 bytes menos significativos del re-
gistro EAX, llamado AX, se almacena el valor 5000, que será el parámetro de
la función Sleep. Después se realiza un PUSH en la pila del parámetro y una
llamada a la función con la instrucción CALL.
Traduciendo este código a hexadecimal obtendremos la siguiente shellcode:
\x31\xc0\xbb\x86\x4e\xfd\x75\x66\xb8\x88\x13\x50\xff\xd3
Shellcode para Windows
© FUOC • PID_00208393 13 Shellcodes
2. Shellcodes por entrada estándar
Como se pudo comprobar en el módulo dedicado a Stack Overflow, existe la
imposibilidad de introducir caracteres no imprimibles por pantalla. En aquel
ejemplo no pudimos reconducir el flujo del programa hacia las zonas de me-
moria que se deseaba debido a la limitación de la consola para representar
caracteres no imprimibles por pantalla. Este mismo problema nos lo vamos a
encontrar cuando queramos escribir shellcodes y las instrucciones que quera-
mos introducir sean representadas por caracteres no imprimibles.
© FUOC • PID_00208393 14 Shellcodes
3. Shellcodes alfanuméricas
Existen programas IDS [Sistemas de detección de intrusiones] que detectan el en-
vío de caracteres "anormales" y descartan los paquetes considerados peligrosos
evitando, en algunos casos, que las shellcodes lleguen al software vulnerable.
Existen, pues, técnicas que permiten la generación de shellcodes solo mediante
el uso del juego de caracteres alfabéticos y dígitos numéricos [A-Za-z0-9] para
evitar la detección por parte de los IDS.
El objetivo es que por la red solo circulen caracteres alfanuméricos y que cada
carácter sea trasladado a su código hexadecimal, es decir, a una instrucción de
ensamblador. Lógicamente, el código ensamblador está formado por muchas
más instrucciones de las que se pueden direccionar con las letras y los núme-
ros, pero existen equivalencias entre instrucciones. Así, como se ha visto en
los ejemplos anteriores, es posible crear una instrucción MOV EAX,0 como XOR
EAX,EAX. Las dos instrucciones consiguen el mismo objetivo: que todos los
bits del registro EAX se pongan a cero.
Se puede ver a continuación una tabla con las correspondencias entre los ca-
racteres imprimibles por pantalla y las instrucciones de ensamblador con las
que se corresponden:
Hexadecimal Carácter Instrucción
30 0 xor <r/m8>,<r8>
31 1 xor <r/m32>,<r32>
32 2 xor <r8>,<r/m8>
33 3 xor <r32>,<r/m32>
34 4 xor al,<imm8>
35 5 xor eax,<imm32>
36 6 ss: (Segment Override Prefix)
37 7 Aaa
38 8 cmp <r/m8>,<r8>
39 9 cmp <r/m32>,<r32>
41 A inc ecx
42 B inc edx
43 C inc ebx
44 D inc esp
Equivalencias hexadecimal, alfanumérico y ensamblador
© FUOC • PID_00208393 15 Shellcodes
Hexadecimal Carácter Instrucción
45 E inc ebp
46 F inc esi
47 G inc edi
48 H dec eax
49 I dec ecx
4A J dec edx
4B K dec ebx
4C L dec esp
4D M dec ebp
4E N dec esi
4F O dec edi
50 P push eax
51 Q push ecx
52 R push edx
53 S push ebx
54 T push esp
55 U push ebp
56 V push esi
57 W push edi
58 X pop eax
59 Y pop ecx
5A Z pop edx
61 A Popa
62 B bound <...>
63 C arpl <...>
64 D fs: (Segment Override Prefix)
65 E gs: (Segment Override Prefix)
66 F o16: (Operand Size Override)
67 G a16: (Address Size Override)
68 H push <imm32>
69 I imul <...>
6A J push <imm8>
Equivalencias hexadecimal, alfanumérico y ensamblador
© FUOC • PID_00208393 16 Shellcodes
Hexadecimal Carácter Instrucción
6B K imul <...>
6C L insb <...>
6D M insd <...>
6E N outsb <...>
6F O outsd <...>
70 P jo <disp8>
71 Q jno <disp8>
72 R jb <disp8>
73 S jae <disp8>
74 T je <disp8>
75 U jne <disp8>
76 V jbe <disp8>
77 W ja <disp8>
78 X js <disp8>
79 Y jns <disp8>
7A Z jp <disp8>
Equivalencias hexadecimal, alfanumérico y ensamblador
En esta tabla se han usado las siguientes nomenclaturas:
• <r8>: Un registro de 8 bits
• <r32>: Registro de 32 bits
• <r/m8>: Marca un registro o un valor en memoria (puntero) de 8 bits
• <r/m32>: Registro o valor en memoria (puntero) de 32 bits
• <imm8>: Indica un valor inmediato de 8 bits
• <imm32>: Indica un valor inmediato de 32 bits
• <disp8>: Desplazamiento de 8 bits
• <...>: Denota la posibilidad de tener que introducir un operando
Como se puede observar, el conjunto de instrucciones es bastante limitado y
no disponemos de instrucciones tan importantes como MOV ni ADD o SUB (solo
podremos incrementar o decrementar los valores de los registros), además de
tener algunas limitaciones en otras funciones importantes como POP (solo
para registros EAX, ECX y EDX), JMP o CMP, con las que no podemos realizar
algunos tipos de comparaciones.
© FUOC • PID_00208393 17 Shellcodes
Para todas estas operaciones habrá que buscar equivalencias de instrucciones
a la hora de generar el código de la shellcode.
© FUOC • PID_00208393 18 Shellcodes
4. Un ejemplo de Shellcode
Con todos los conceptos vistos en el módulo actual podemos empezar a escri-
bir nuestra primera shellcode para el siguiente código vulnerable:
#include <stdio.h>
int main(int argc, char *argv[])
{
char nombre[1024];
if(argc < 2)
{
printf("Uso: [Link] <nombre>\n");
return -1;
}
strcpy(nombre, argv[1]);
printf("Hola %s!\n", nombre);
return 0;
}
Código vulnerable a stack overflow
Como nota singular en este código tenemos que el nombre, que es la variable
vulnerable a desbordamiento, ocupa ahora 1024 bytes. Se ha definido con
esta longitud para poder representar mejor el tamaño disponible en memoria.
Además, se ha definido con un tamaño suficientemente grande como para
poder acoger todo el código de la shellcode de la práctica.
Introducir por consola 1024 caracteres para sobrescribir la dirección de re-
torno, que en realidad serán 1036 si tenemos en cuenta los 12 bytes que sepa-
ran el final de las variables con la dirección de retorno, puede ser algo tedioso
y aburrido, por lo que es común utilizar un lenguaje interpretado como Perl
para facilitar esta tarea.
Como se puede ver en la siguiente figura, es posible pasar como parámetro
al programa vulnerado el resultado de la ejecución de un script Perl. Aprove-
chando esta característica se hará que el programa Perl devuelva la cadena que
genera la shellcode a explotar en el programa vulnerable. La sentencia quedaría
como sigue:
© FUOC • PID_00208393 19 Shellcodes
Desbordamiento de memoria mediante salida de un script en Perl
Nuestro objetivo ahora es generar un código que se pueda ejecutar, haciendo
que la dirección de retorno sea un punto de la memoria que contenga instruc-
ciones ejecutables.
Vamos a empezar con un ejemplo sencillo, haciendo una llamada a la función
Sleep para que detenga la ejecución del programa durante el número de milise-
gundos que nosotros le indiquemos. El código ya se especificó anteriormente
y también el volcado hexadecimal que le correspondía, pero para que se pueda
seguir el ejemplo paso por paso vamos a mostrar cómo obtener la shellcode
desde el inicio.
© FUOC • PID_00208393 20 Shellcodes
5. Dirección de la función a llamar
Lo primero que deberíamos obtener es la dirección de la función Sleep en
nuestro sistema. Para ello se usa el programa arwin.c, que nos mostrará la
dirección que ocupa Sleep en el sistema. Como es una función básica de la
API, esta se encuentra en la librería dinámica [Link].
Dirección que ocupa Sleep en la memoria
Como se puede ver, en este entorno la dirección obtenida ha sido diferente a
la obtenida en el otro equipo. En este caso, 0x7c802446.

También podría gustarte