¿Cómo un desbordamiento de búfer puede llevar a la ejecución remota de código en 64 bits?

6

Tengo el siguiente pseudo código resumido en C89 de una biblioteca de servidor ssh que proporciona solo acceso a cosas como git-shell ( /bin/bash se reemplaza con el programa que se ejecuta, por lo que no es posible hacer otra cosa ) :

struct _raw_uncapped_ssh_string { // no limit on the size of the string;
    uint32_t len;
    char non_null_terminated_string[]; // by protocol design it have a minimum length of 1
};
typedef struct _raw_uncapped_ssh_string raw_ssh_string;
union buffer {
       void * uncapped_zlib_decompressed_network_data; 
       // yes, the size is uncapped, so it’s possible to put 4Gb of
       // data in it that would be copied later into memory. zlib 
       // allow easily to turn some Mb in Gb of data, but it’s not 
       // the point of the question.

       raw_ssh_string st;
};
get_command (compressed_network_data) {
    size_t len;
    char * command;
    buffer string=uncompress_to_buffer(compressed_network_data);
    len=ntohl(string.st.len)+1;
    command=malloc(len+1);
    command[len]=0;

    // here’s the point, both the string length and content as 
    // well it’s supplied size is controlled by the attacker.
    memcpy(command,string.st.data,len); 

    return command;
}

Aquí se explica cómo se ejecuta el comando más tarde (la cadena command no se modifica después de get_command() ) .

const char *args[]={"/bin/bash",command,NULL}; // /bin/bash isn’t the shell, it has been replaced by git‑shell.

// redirect the program output to the network.
dup2(stdin, 0);
dup2(stdout,1);
dup2(stdout,2);
close(stdin);
close(stdout);

//if this return execution failed and print an error message
return execv(args[0],(char * const *)args); // I don’t know which is the system, so I can’t know about the libc behaviour.

No puedo hacer memcpy(command,string.st.data,0) ya que el tercer miembro de memcpy tiene un tamaño mínimo de 1, y en mi contexto, size_t usa un entero de 64 bits, no puedo realizar un desbordamiento de búfer, ya que hay len .

Todo lo que puedo hacer es establecer len en un valor mayor que el asignado a string.st.data . Este es un flujo insuficiente de búfer que me permite leer la memoria no asignada.
Puedo leer la memoria del servidor, sin embargo, no puedo ver qué datos confidenciales puede contener un servidor ssh público (en mi caso, la lista de usuarios que pueden realizar ssh es pública) .

Entonces, ¿un flujo insuficiente de búfer en memcpy permite la ejecución remota de código?

    
pregunta user2284570 30.10.2015 - 15:31
fuente

2 respuestas

2

En general, no, no se puede usar un desbordamiento de búfer para la ejecución remota de código. Dado que los datos controlados por el atacante nunca dejan el espacio asignado para ellos, nunca tienen la capacidad de asumir el flujo de ejecución del programa.

Un desbordamiento de búfer tiene el potencial para otros tipos de ataques, como la divulgación de información (si el programa cuenta con el contenido original del búfer eliminado por los nuevos datos).

    
respondido por el Mark 17.12.2015 - 07:53
fuente
0
  

¿un desbordamiento de búfer en memcpy permite la ejecución remota de código?

Un desbordamiento de búfer puede permitir que un atacante sobrescriba los punteros de función ubicados en las regiones de memoria antes de la matriz en cuestión. Si esos punteros de función están diseñados para apuntar a shellcode, ese shellcode puede ejecutarse cuando se invocan más adelante.

Además, la expresión array[-u] donde u tiene un tipo unsigned puede resultar en un acceso más allá del final de la matriz (un desbordamiento de búfer ) cuando -u es igual o mayor que el número de elementos.

En este fragmento de código un tanto oscuro, parece que solo hay riesgo de desbordamiento del búfer cuando int tiene un dominio más amplio que uint32_t , ya que ntohl(string.st.len)+1 causaría que el valor uint32_t se convierta en int tipo. Si está buscando una garantía contra desbordamiento de búfer , use el sufijo literal U integer (es decir, ntohl(string.st.len)+1U ).

Si considera que ntohl(string.st.len) puede devolver uno menos que el valor máximo para ese tipo sin signo, entonces len=ntohl(string.st.len)+1 resultará en el valor máximo, malloc(len+1) causará ajuste sin firmar , por lo que Terminaré invocando malloc(0) y luego command[len]=0 escribirá bien y verdaderamente más allá del final de la matriz. Luego, por supuesto, también tendrá un problema con memcpy(command,string.st.data,len); .

Los desbordamientos y desbordamientos de búfer no son el único riesgo. Si no verifica el valor de retorno de malloc , y malloc devuelve NULL , se puede usar una diferencia de puntero nulo para causar la ejecución de código arbitrario. Esto implica que debe tener un método para comunicar las fallas malloc a la persona que llama. También implica que podría usar ese mismo método para verificar y comunicar el problema de ajuste al interlocutor.

    
respondido por el autistic 18.04.2017 - 06:28
fuente

Lea otras preguntas en las etiquetas