Shellcode
Una shellcode es un conjunto de órdenes programadas generalmente en lenguaje ensamblador y trasladadas a opcodes (conjunto de valores hexadecimales) 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.
Término
El término shellcode deriva de su propósito general, esto era una porción de un exploit utilizada para obtener una shell. Este es actualmente el propósito más común con que se utilizan.
Ejemplo de shellcode en Pauscal
Ejemplo de shellcode en C
En el siguiente ejemplo se muestra una shellcode contenida en un array de un programa escrito en lenguaje C:
char shellcode[]= "\x31\xc0" /* xorl %eax,%eax */ "\x31\xdb" /* xorl %ebx,%ebx */ "\x31\xc9" /* xorl %ecx,%ecx */ "\xb0\x46" /* movl $0x46,%al */ "\xcd\x80" /* int $0x80 */ "\x50" /* pushl %eax */ "\x68""/ash" /* pushl $0x6873612f */ "\x68""/bin" /* pushl $0x6e69622f */ "\x89\xe3" /* movl %esp,%ebx */ "\x50" /* pushl %eax */ "\x53" /* pushl %ebx */ "\x89\xe1" /* movl %esp,%ecx */ "\xb0\x0b" /* movb $0x0b,%al */ "\xcd\x80" /* int $0x80 */ ;
Así tenemos que una shellcode es código máquina escrito en notación hexadecimal. Posteriormente se utilizan dentro de programas escritos en C, como en el siguiente shellcode de ejemplo:
// shellcode.c // compilar con gcc shellcode.c -o shellcode void main() { ((void(*)(void)) { "\xeb\x19\x31\xc0\x31\xdb\x31\xd2\x31\xc9" "\xb0\x04\xb3\x01\x59\xb2\x21\xcd\x80\x31" "\xc0\xb0\x01\x31\xdb\xcd\x80\xe8\xe2\xff" "\xff\xff\x76\x69\x73\x69\x74\x61\x20\x68" "\x74\x74\x70\x3a\x2f\x2f\x68\x65\x69\x6e" "\x7a\x2e\x68\x65\x72\x6c\x69\x74\x7a\x2e" "\x63\x6c\x20\x3d\x29" } )(); }
Información
Las shellcodes deben ser cortas para poder ser inyectadas dentro de la pila, que generalmente suele ser un espacio reducido.
Las shellcodes se utilizan para ejecutar código aprovechando ciertas vulnerabilidades en el código llamadas desbordamiento de búfer. Principalmente el shellcode se programa para permitir ejecutar un intérprete de comandos en el equipo afectado.
Es común que en la compilación de una shellcode se produzcan bytes nulos, los cuales deben ser eliminados de la misma, ya que frenarían la ejecución de la shellcode. Para ello el programador se vale de diversas técnicas, como remplazar las instrucciones que genera bytes NULL por otras que no lo hagan o realizar una operación XOR, mover hacia registros más pequeños (como AH, AL), y de esta forma permitir que la shellcode sea realmente inyectable.