Ejecución remota de código en git 2.7.0 y anteriores

Recientemente se ha descubierto un desbordamiento de pila que afecta a todas las versiones de Git anteriores a la 2.7.1 y que podría permitir la ejecución remota de código, tanto en cliente como en servidor, si se sube o se clona un repositorio con un nombre de fichero muy largo o un número elevado de árboles anidados.

El problema original se detectó y publicó inicialmente en Pastebin (http://pastebin.com/UX2P2jjg):

char *path_name(const struct name_path *path, const char *name) // by design, name_path->len is a 32 bits int, but this doesn’t concern name
{
      const struct name_path *p;
      char *n, *m;
      int nlen = strlen(name); // the size is converted to a positive number (the correct size was allocated previously with an unsigned long). I got 705804100
      int len = nlen + 1;
 
      for (p = path; p; p = p->up) { //loop is skipped (except for the ᴄᴠᴇ-2016-2324 case which is fixed since 2.7.1 in February 2016)
          if (p->elem_len)
              len += p->elem_len + 1;
      }
      n = xmalloc(len); // if len is negative, it will also be converted to a negative 64 bits integer *(which explains it is normally trying to allocate serveral Pb of ram most of the time)* which will be read as positive after that. // but this isn’t the run case that is interesting here.
      m = n + len - (nlen + 1); // the size of m is lower than name
      strcpy(m, name); // strcpy rely on the null terminating character. The result is written in an unallocated memory from heap. This is the definition of heap overflow enabling server side remote code execution if name[] contains assembly, and have the correct size. This open the way to defeat canaries aslr, and nx combined see http://security.stackexchange.com/q/20497/36301#comment182004_20550
      for (p = path; p; p = p->up) {
          if (p->elem_len) {
              m -= p->elem_len + 1;
              memcpy(m, p->elem, p->elem_len);
              m[p->elem_len] = '/';
          }
      }
      return n;
}

Como resultado de ésto, para evitar el desbordamiento, se sustituyó strcpy por memcpy para que el valor de la asignación en memoria de "len" coincidiera con el número de bytes a escribir (https://github.com/git/git/commit/34fa79a6cde56d6d428ab0d3160cb094ebad3305):

char *path_name(const struct name_path *path, const char *name)
{
         const struct name_path *p;
         char *n, *m;
         int nlen = strlen(name);
         int len = nlen + 1;

         for (p = path; p; p = p->up) {
                 if (p->elem_len)
                         len += p->elem_len + 1;
         }
         n = xmalloc(len);
         m = n + len - (nlen + 1);
         memcpy(m, name, nlen + 1);
         
         for (p = path; p; p = p->up) {
                 if (p->elem_len) {
                         m -= p->elem_len + 1;
                         memcpy(m, p->elem, p->elem_len);
                         m[p->elem_len] = '/';
                 }
         }
         return n;
}

Sin embargo, si veis el código "len" se puede cambiar debido al primer loop sumando los valores para obtener un valor más pequeño que el asignado al buffer (ej.
A=2^31-5, B=2^31-5, C=20A=2^31-5, B=2^31-5, C=20 daría len=10), por lo que en la versión 2.7.1 se decidió eliminar path_name() y la comprobación de size_t/overflow en tree-diff.c.

El problema es que varios meses después de la supuesta corrección, la mayoría de las distribuciones Linux no lo han resuelto todavía para su rama estable.

Esto podría afectar a Github o Bitbucket o, incluso peor, a instalaciones en hosting propios como por ejemplo de Gitlab.
Por lo que si trabajas con un repositorio git tendrías que tener mucho cuidado con estas vulnerabilidades: CVE-2016-2324, CVE-2016-2315 .

Exploit is coming...

Fuente:
- [oss-security] server and client side remote code execution through a buffer overflow in all git versions before 2.7.1 (unpublished ᴄᴠᴇ-2016-2324 and ᴄᴠᴇ‑2016‑2315)
- Remote Code Execution in all git versions (client + server) < 2.7.1: CVE-2016-2324, CVE-2016-2315 


Actualización: Como nos comenta Laël Cellier incluso la versión 2.7.3 seguía vulnerable con path_name(). Parece que en la versión 2.8.0-rc0 se ha solucionado pero no obstante y como indica lo mejor es compilar de nuevo del master branch de

https://git.kernel.org/cgit/git/git.git/.

2 comentarios :

  1. No abla Español

    As I told, even 2.7.3 is vulnerable. http://www.openwall.com/lists/oss-security/2016/03/16/10

    The only way to fix is to use the developmentt repository from git.kernel.org

    ResponderEliminar
    Respuestas
    1. thx so much for your update. So, was path_name definitely removed in v2.8.0-rc0?

      Eliminar