[UNIX] chmlib Buffer Overflow (Technical Details)

From: SecuriTeam (support_at_securiteam.com)
Date: 10/31/05

  • Next message: SecuriTeam: "[NT] Network Appliance iSCSI Authentication Bypass"
    To: list@securiteam.com
    Date: 31 Oct 2005 08:59:31 +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

    - - - - - - - - -

      chmlib Buffer Overflow (Technical Details)
    ------------------------------------------------------------------------

    SUMMARY

    CHMLIB is "a library for dealing with Microsoft ITSS/CHM format files.
    Right now, it is a very simple library, but sufficient for dealing with
    all of the .chm files I've come across. Due to the fairly well-designed
    indexing built into this particular file format, even a small library is
    able to gain reasonably good performance indexing into ITSS archives".

    chmlib has been found to be vulnerable to a buffer overflow, allowing
    attacker to execute arbitrary code.

    DETAILS

    Vulnerable Systems:
     * chmlib version 0.36 and prior.

    Immune Systems:
     * CHM lib version 0.37 (download
    <http://morte.jedrea.com/%7Ejedwin/projects/chmlib/chmlib-0.37.2.tgz>
    here)
     * CHM lib version 0.37.2 (download
    <http://morte.jedrea.com/%7Ejedwin/projects/chmlib/chmlib-0.37.tgz> here)

    0. chm_lib.c: _chm_decompress_block(struct chmFile *h, UInt64 block,UChar
    **ubuffer)
    1. see cmpLen and cbuffer declaration
    2. call to _chm_get_cmpblock_bounds(h, block, &cmpStart, &cmpLen) to set
    cmpLen
    3. cmpLen is used to offset write operations in cbuffer
    (_chm_fetch_bytes(h, cbuffer, cmpStart, cmpLen))
    4. if cmpLen > h->reset_table.block_len + 6144 the buffer overflows
    5. as we can supply the fd data, exploitation is possible and an attacker
    can execute arbitrary code.

    Vulnerable code:
    /* decompress the block. must have lzx_mutex. */
    static Int64 _chm_decompress_block(struct chmFile *h,
                                       UInt64 block,
                                       UChar **ubuffer)
    {
    ..
        UChar cbuffer[h->reset_table.block_len + 6144]; /* compressed
    buffer */
        Int64 cmpLen; /* compressed
    len */

    ..
    ..
    ..
    ..

        if (! _chm_get_cmpblock_bounds(h, block, &cmpStart, &cmpLen)
    ||
            _chm_fetch_bytes(h, cbuffer, cmpStart, cmpLen) != cmpLen
    ||
            LZXdecompress(h->lzx_state, cbuffer, lbuffer, (int)cmpLen,
                          (int)h->reset_table.block_len) != DECR_OK)
        {
    ..

    -----------------------------

    /* get the bounds of a compressed block. return 0 on failure */
    static int _chm_get_cmpblock_bounds(struct chmFile *h,
                                 UInt64 block,
                                 UInt64 *start,
                                 Int64 *len)
    {
        UChar buffer[8], *dummy;
        unsigned int remain;

        /* for all but the last block, use the reset table */
        if (block < h->reset_table.block_count-1)
        {

            ...
            ...

            /* unpack the end address */
            dummy = buffer;
            remain = 8;
            if (_chm_fetch_bytes(h, buffer,
                             (UInt64)h->data_offset
                                    + (UInt64)h->rt_unit.start
                                    + (UInt64)h->reset_table.table_offset
                                    + (UInt64)block*8 + 8,
                             remain) != remain
    ||
                !_unmarshal_int64(&dummy, &remain, len))
                return 0;
        }

        /* for the last block, use the span in addition to the reset table */
        else
        {
           ...
        }

        /* compute the length and absolute start address */
        *len -= *start;
        *start += h->data_offset + h->cn_unit.start;

        return 1;
    }

    --------------
    /*
     * dest(len) is read out of the fd
    */
    static int _unmarshal_int64(unsigned char **pData,
                                unsigned int *pLenRemain,
                                Int64 *dest)
    {
        Int64 temp;
        int i;
        if (8 > *pLenRemain)
            return 0;
        temp=0;
        for(i=8; i>0; i--)
        {
            temp <<= 8;
            temp |= (*pData)[i-1];
        }
        *dest = temp;
        *pData += 8;
        *pLenRemain -= 8;
        return 1;
    }

    ---------------

    /* utility function to handle differences between {pread,read}(64)? */
    static Int64 _chm_fetch_bytes(struct chmFile *h,
                                  UChar *buf,
                                  UInt64 os,
                                  Int64 len)
    {
        Int64 readLen=0, oldOs=0;
        if (h->fd == CHM_NULL_FD)
            return readLen;

        CHM_ACQUIRE_LOCK(h->mutex);
    ..
        readLen = pread(h->fd, buf, (long)len, (unsigned int)os);
    ..
        CHM_RELEASE_LOCK(h->mutex);
        return readLen;
    }

    Disclosure Timeline:
    24.10.05 - Issue found by Sven Tantau
    25.10.05 - Contacted chmlib maintainer
    25.10.05 - Quick reaction with confirmation
    26.10.05 - New release of chmlib and public disclosure

    Vendor Status:
    chmlib maintainer Jed Wing released a new version 0.37

    ADDITIONAL INFORMATION

    The information has been provided by <mailto:sven@sven-tantau.de> Sven
    Tantau.
    The original article can be found at:
    <http://www.sven-tantau.de/public_files/chmlib/chmlib_20051126.txt>
    http://www.sven-tantau.de/public_files/chmlib/chmlib_20051126.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: "[NT] Network Appliance iSCSI Authentication Bypass"

    Relevant Pages

    • [UNIX] chmlib CHM File Handling Buffer 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 ... " The chmlib library ... The vulnerability specifically exists due to an unchecked memory copy ... Exploitation could allow attackers to execute arbitrary code with the ...
      (Securiteam)
    • [NEWS] Multiple Vendor libchm Page Block Length Memory Corruption Vulnerability
      ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... The 'xchm' program uses CHMlib to display CHM files". ... An attacker would have to first convince the user to view the CHM file ... CHM files contain various tables and objects stored in "pages." ...
      (Securiteam)
    • [Full-disclosure] chmlib exploitable buffer overflow
      ... Vendor-URL: http://morte.jedrea.com/%7Ejedwin/projects/chmlib/ ... chmlib is a small library designed for accessing MS ITSS files. ... static Int64 _chm_decompress_block(struct chmFile *h, ... static int _chm_get_cmpblock_bounds(struct chmFile *h, ...
      (Full-Disclosure)
    • [UNIX] FUSE Information Disclosure
      ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... Lack of range validation in FUSE allows attackers to reveal information ... * Linux kernel 2.2 ... static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes, ...
      (Securiteam)