InfoZip UnZip 6.00 / 6.1c22 Buffer Overflow

Topic created · 1 Posts · 0 Views
  • InfoZip UnZip versions 6.00 and below and 6.1c22 and below suffer from multiple buffer overflow vulnerabilities.
    MD5 | bdf125c9b1ccf7ea7ce8e8e8062e3d85

    SEC Consult Vulnerability Lab Security Advisory < 20180207-0 >  
    title: Multiple buffer overflow vulnerabilities  
    product: InfoZip UnZip  
    vulnerable version: UnZip <= 6.00 / UnZip <= 6.1c22  
    fixed version: 6.10c23  
    CVE number: CVE-2018-1000031,CVE-2018-1000032,CVE-2018-1000033  
    impact: high  
    found: 2017-11-03  
    by: R. Freingruber (Office Vienna)  
    SEC Consult Vulnerability Lab  
    An integrated part of SEC Consult  
    Bangkok - Berlin - Linz - Luxembourg - Montreal - Moscow  
    Kuala Lumpur - Singapore - Vienna (HQ) - Vilnius - Zurich  
    Vendor description:  
    "UnZip is an extraction utility for archives compressed in .zip format (also  
    called "zipfiles"). Although highly compatible both with PKWARE's PKZIP and  
    PKUNZIP utilities for MS-DOS and with Info-ZIP's own Zip program, our  
    primary objectives have been portability and non-MSDOS functionality.  
    UnZip will list, test, or extract files from a .zip archive, commonly found  
    on MS-DOS systems. The default behavior (with no options) is to extract into  
    the current directory (and subdirectories below it) all files from the  
    specified zipfile."  
    InfoZip's UnZip is used as default utility for uncompressing ZIP archives  
    on nearly all *nix systems. It gets shipped with many commerical products on  
    Windows to provide (un)compressing functionality as well.  
    Business recommendation:  
    InfoZip Unzip should be updated to the latest available version.  
    Vulnerability overview/description:  
    1) Heap-based buffer overflow in password protected ZIP archives (CVE-2018-1000035)  
    InfoZip's UnZip suffers from a heap-based buffer overflow when uncompressing  
    password protected ZIP archives. An attacker can exploit this vulnerability  
    to overwrite heap chunks to get arbitrary code execution on the target system.  
    For newer builds the risk for this vulnerability is partially mitigated  
    because modern compilers automatically replace unsafe functions with length  
    checking variants of the same function (for example sprintf gets replaced  
    by sprintf_chk). This is done by the compiler at locations were the length  
    of the destination buffer can be calculated.  
    Nevertheless, it must be mentioned that UnZip is used on many systems  
    including older systems or on exotic architectures on which this protection  
    is not in place. Moreover, pre-compiled binaries which can be found on the  
    internet lack the protection because the last major release of InfoZip's  
    UnZip was in 2009 and compilers didn't enable this protection per default at  
    that time. The required compiler flags are also not set in the Makefile of  
    UnZip. Compiled applications are therefore only protected if the used compiler  
    has this protection enabled per default which is only the case with modern  
    To trigger this vulnerability (and the following) it's enough to uncompress  
    a manipulated ZIP archive. Any of the following invocations can be used to  
    trigger and abuse the vulnerabilities:  
    >unzip -p  
    >unzip -t  
    2) Heap-based out-of-bounds write (CVE-2018-1000031)  
    This vulnerability only affects UnZip 6.1c22 (next beta version of UnZip).  
    InfoZip's UnZip suffers from a heap-based out-of-bounds write if the  
    archive filename does not contain a .zip suffix.  
    3) Heap/BSS-based buffer overflow (Bypass of CVE-2015-1315) (CVE-2018-1000032)  
    This vulnerability only affects UnZip 6.1c22 (next beta version of UnZip).  
    InfoZip's UnZip suffers from a heap/BSS-based buffer-overflow which  
    can be used to write null-bytes out-of-bound when converting  
    attacker-controlled strings to the local charset.  
    4) Heap out-of-bounds access in ef_scan_for_stream (CVE-2018-1000033)  
    This vulnerability only affects UnZip 6.1c22 (next beta version of UnZip).  
    InfoZip's UnZip suffers from a heap out-of-bounds access  
    5) Multiple vulnerabilities in the LZMA compression algorithm (CVE-2018-1000034)  
    This vulnerability only affects UnZip 6.1c22 (next beta version of UnZip).  
    InfoZip's UnZip suffers from multiple vulnerabilities in the LZMA  
    implementation. Various crash dumps have been supplied to the vendor  
    but no further analysis has been performed.  
    Proof of concept:  
    1) Heap-based buffer overflow in password protected ZIP archives (CVE-2018-1000035)  
    Unzipping a malicious archive results in the following output:  
    (On Ubuntu 16.04 with UnZip 6.0 which was installed via aptitude install unzip)  
    *** buffer overflow detected ***: unzip terminated  
    ======= Backtrace: =========  
    Function names can be mapped to the backtrace by compiling the application  
    with debug symbols:  
    (gdb) backtrace  
    #0  0x000000000040c706 in UzpPassword ()  
    #1  0x00000000004043ce in decrypt ()  
    #2  0x000000000040731c in extract_or_test_entrylist ()  
    #3  0x00000000004094af in extract_or_test_files ()  
    #4  0x00000000004149a5 in do_seekable ()  
    #5  0x000000000041540f in process_zipfiles ()  
    #6  0x0000000000403921 in unzip ()  
    The vulnerability resides inside the UzpPassword function in the following  
    code snippet (file ./fileio.c):  
    [1591]  if ((prompt = (char *)malloc(2*FILNAMSIZ + 15)) != (char *)NULL) {  
    [1592]    sprintf(prompt, LoadFarString(PasswPrompt),  
    [1593]          FnFilter1(zfn), FnFilter2(efn));  
    [1595]  }            
    The allocation at line 1591 allocates a fixed size buffer and then writes into  
    it at line 1592. It writes the following format string (PasswPrompt) into  
    the buffer: "[%s] %s password: "  
    This string has a length of 15 including the null-termination which explains  
    the +15 in the allocation. The developer allocated 2*FILENAMESIZ which  
    corresponds to 2 * PATH_MAX for the two format strings (zfn and efn).  
    zfn is the archive filename and can therefore not exceed PATH_MAX.  
    efn is the current processed filename inside the ZIP archive which should  
    typically be smaller than PATH_MAX for normal files. However, since an  
    attacker can manipulate the archive file the name can arbitrarily be chosen  
    which leads to a heap-based buffer overflow.  
    As already mentioned, modern compilers replace unsafe functions with  
    safe alternatives as a defense in depth mechanism.  
    This feature is called BOSC (Built-in object size checking) and is part  
    of the FORTIFY_SOURCE=2 protection.  
    The following link shows the source code (and vulnerability) inside  
    the Ubuntu package:  
    By checking the installed compiled binary the following code can be seen:  
    (UnZip 6.0 from Ubuntu 16.04)  
    0x40bfc6:    mov    edi,0x200f  
    0x40bfcb:    mov    r13,r8  
    0x40bfce:    mov    QWORD PTR [rsp+0x8],r9  
    0x40bfd3:    call   0x401d30 <[[email protected]](/cdn-cgi/l/email-protection)>  
    0x40c01a:    mov    edx,0x200f  
    0x40c01f:    mov    esi,0x1  
    0x40c024:    xor    eax,eax  
    0x40c026:    call   0x401f40 <[[email protected]](/cdn-cgi/l/email-protection)>  
    The code allocates 0x200f (=4096*2 + 15) bytes but the unsafe sprintf  
    function was replaced with the length-checking sprintf_chk() function  
    which receives as argument the size of the buffer (0x200f at address  
    0x40c01a). The risk is therefore mitigated on Ubuntu (and other modern  
    operating systems), at least with the currently used compiler default flags.  
    However, many pre-compiled UnZip binaries can be found on the internet  
    which are not compiled with this protection.  
    For example, the following three links are the first links which can be  
    found when searching for InfoZip UnZIP on the internet and which contain  
    unprotected binaries:  
    2) Heap-based out-of-bounds write (CVE-2018-1000031)  
    When uncompressing ZIP archives the following code gets executed  
    (file fileio.c:345 function set_zipfn_sgmnt_name() in UnZip 6.1c22):  
    #define SGMNT_NAME_BOOST 8  
    if (G.zipfn_sgmnt == NULL)  
    [1]    G.zipfn_sgmnt_size = (int)strlen(G.zipfn)+ SGMNT_NAME_BOOST;  
    if ((G.zipfn_sgmnt = izu_malloc(G.zipfn_sgmnt_size)) == NULL)  
    [2]  zfstrcpy(G.zipfn_sgmnt, G.zipfn);  
    /* Expect to find ".zXX" at the end of the segment file name. */  
    [3]  sufx_len = IZ_MAX( 0, ((int)strlen(G.zipfn_sgmnt)- 4));  
    [4]  suffix = G.zipfn_sgmnt+ sufx_len;  
    else  // No .zip extension  
    [5]    zfstrcpy( (suffix+ sufx_len), ZSUFX);  
    [6]    suffix += sufx_len+ 2;  
    /* Insert the next segment number into the file name (G.zipfn_sgmnt). */  
    [7]  sprintf(suffix, "%02d", (sgmnt_nr+ 1));  
    G.zipfn is the filename / path of the archive file. Line [1] allocates space  
    for this name plus 8 (SGMNT_NAME_BOOST). Line [2] copies the name.  
    [3] and [4] calculate the end address minus 4 which should point to a suffix  
    if one is present. After [4] the variable suffix already points to this  
    address. However, line [5] adds sufx_len again to suffix, the write target  
    is therefore the base address + 2*(allocation_length - 4) but the buffer  
    can only hold allocation_len bytes.  
    Line [7] is another out-of-bounds write because of line [6].  
    Memory trace of the crash:  
    #1 0xf7af3c2f in memcpy (/usr/lib/i386-linux-gnu/  
    #2 0x80969be in set_zipfn_sgmnt_name unzip610c22/fileio.c:424  
    #3 0x808eb82 in find_local_header unzip610c22/extract.c:4469  
    #4 0x808eb82 in extract_or_test_entrylist unzip610c22/extract.c:4745  
    #5 0x808eb82 in extract_or_test_files unzip610c22/extract.c:5698  
    #6 0x80cf6ca in extract_archive_seekable unzip610c22/process.c:1314  
    #7 0x80cf6ca in extract_archive unzip610c22/process.c:1465  
    #8 0x80d5676 in process_zipfiles unzip610c22/process.c:2033  
    #9 0x80636a2 in unzip unzip610c22/unzip.c:1840  
    #10 0x804a5b6 in main unzip610c22/unzip.c:1280  
    #11 0xf78cb636 in __libc_start_main (/lib/i386-linux-gnu/  
    Please note that this vulnerability must not lead to a crash. If the  
    overwritten memory is not used, the program works as expected.  
    3) Heap/BSS-based buffer overflow (Bypass of CVE-2015-1315) (CVE-2018-1000032)  
    During parsing ZIP archives the function charset_to_intern() can be called  
    (unix/Unix.c:2427) with the "string" argument pointing to attacker  
    controlled data. This function converts the string in-place to another  
    charset (string is an INOUT argument).  
    The following code performs this task in the function:  
    [1]    slen = strlen(string);  
    [2]    s = string;  
    [3]    dlen = buflen = 2 * slen;  
    [4]    d = buf = izu_malloc(buflen + 1);  
    if (d)  
    [5]      memset( buf, 0, buflen);  
    /* 2015-02-12 William Robinet, SMS.  CVE-2015-1315.  
    * Added FILNAMSIZ check to avoid buffer overflow. Better would  
    * be to pass in an actual destination buffer size.  
    [6]      if ((iconv(cd, &s, &slen, &d, &dlen) != (size_t)-1) &&  
    [7]       (strlen(buf) < FILNAMSIZ))  
    [8]        strncpy(string, buf, buflen);  
    The input string pointer is stored in the variable "string" and "s" (see [2]).  
    Line [6] tries to convert the input ("s") via iconv() to another charset.  
    The destination is "d" / "buf" (see line [4]).  
    This destination buffer has a size of two times the input length plus one ([3]).  
    The first problem can be found in line [5] which just initializes "buflen" bytes  
    and not "buflen+1" bytes. Consider the input string is empty, therefore slen=0.  
    This will allocate 1 byte at line [4] because of the +1. However, [5] calls  
    memset with buflen=0 which leaves the 1-byte buffer uninitialized. In line [7]  
    strlen() can therefore access data out-of-bounds if the uninitialized byte does  
    not contain a null-byte. This flaw is not critical because it can just crash the  
    application. Nevertheless, it should be fixed.  
    The second problem is harder to identify. The function do_string() is used to  
    parse strings from ZIP archives. If the option DS_FN gets passed, the string  
    is written into the filename[] array from the global variable G.  
    The code at extract.c:5584 (in the function extract_or_test_files()) calls  
    for example this function with this option:  
    do_string(__G__ G.crec.filename_length, DS_FN)) != PK_COOL)  
    Inside do_string() the following code can be found (fileio.c:3225):  
    Ext_ASCII_TO_Native(G.filename, G.pInfo

    hostnum, G.pInfo

    hostver, G.pInfo->HasUxAtt, (option == DS_FN_L)); The "Ext_ASCII_TO_Native" is a define which redirects to charset_to_intern(). The first argument (G.filename in this case) is passed to this function and can be accessed with the "string" argument in the above code. At line [6] iconv() is used to convert the input string from one charset (e.g.: CP850) to another (e.g.: UTF-8). Therefore "buf" contains the converted string after this call. With line [8] this converted string should be copied over the original location from the argument (G.filename in our case). The strncpy at [8] limits the number of written characters to buflen. Because of [3] buflen is two times the input length and therefore a buffer overflow can happen (the real size of the input buffer is not passed to the function). This vulnerability was CVE-2015-1315 and an additional check was added to prevent this buffer overflow. The additional check at [7] checks the length of the converted string with this line: [7] (strlen(buf) < FILNAMSIZ)) Only if this check is passed the code at [8] gets executed: [8] strncpy(string, buf, buflen); This should logically limit the number of bytes which can be written to be smaller than FILNAMSIZ (even if the wrong, higher number, is passed to strncpy). For example: G.filename is defined in globals.h:372 (inside the Uz_Globs struct): char filename[FILNAMSIZ]; FILNAMSIZ is defined in unzpriv.h and is equal to PATH_MAX (4096). Therefore, filename can hold a buffer of size 4096. When the above code gets executed and G.filename gets converted to another charset, this code gets executed: [6] if ((iconv(cd, &s, &slen, &d, &dlen) != (size_t)-1) && [7] (strlen(buf) < FILNAMSIZ)) { [8] strncpy(string, buf, buflen); } Let's assume that our input string had a length of 2940. Because of [3] buflen will be 5880 (2*2940). That means if [8] is reached a strncpy with a limit of 5880 gets executed, however, the destination buffer only has a size of 4096 bytes (G.filename). The check at [7] should protect against this because if strlen(buf) (the source from strncpy) is bigger or equal than FILNAMSIZ (4096), the strncpy does not get executed. And since strncpy just copies until the first null-byte, it should just be possible to copy at maximum strlen(buf) bytes in this strncpy. This assumption is wrong though. Strncpy() always writes n bytes - in the above case it will always write 5880 bytes and therefore a buffer overflow will always occur. This behavior can be found in the manpage of strncpy: "If the length of src is less than n, strncpy() writes additional null bytes to dest to ensure that a total of n bytes are written." The strncpy can therefore be used to write null-bytes out-of-bound in the BSS or heap segment. Since the input string length is under attacker control, the write length can be manipulated. That means that an attacker can perform a partial overwrite to exploit this vulnerability. For example, the attacker can overwrite data in the Uz_Globs struct after G.filename with null-bytes. One attack target can be heap addresses. They can be partially overwritten (lower bytes) to change the heap address to point to an attacker controlled heap chunk to get control over the data and therefore also over the execution. 4) Heap out-of-bounds access in ef_scan_for_stream (CVE-2018-1000033) The first two arguments to the function ef_scan_for_stream() (extract.c:1167) are: ef_ptr and ef_len. This function is for example called at: extract.c:4795 sts = ef_scan_for_stream( G.extra_field, (long)G.lrec.extra_field_length, &btmp_siz, &bitmap[ 0], &xlhdr, &cmnt); The second argument (ef_len) stores the length / size of the first argument (ef_ptr) and access checks must be performed to ensure that no out-of-bounds access occurs. Code line extract.c:1233 can access data out-of-bounds because length checks are missing: bitmap = *(ef_ptr+ (data_byte++)); Debugger output: Program received signal SIGSEGV, Segmentation fault. ef_scan_for_stream (...) at extract.c:1233 1233 bitmap = *(ef_ptr+ (data_byte++)); (gdb) print /x ef_ptr $10 = 0x7ffff7ed5f3b (gdb) print /x data_byte $11 = 0xc6 (gdb) print /x ef_len $12 = 0xc5 5) Multiple vulnerabilities in the LZMA compression algorithm (CVE-2018-1000034) Invalid access attempts can occur at: szip/LzmaDec.c:275 - IF_BIT_0(probLen) szip/LzmaDec.c:242 - IF_BIT_0(prob) szip/LzmaDec.c:217 - IF_BIT_0(prob) szip/LzmaDec.c:299 - TREE_6_DECODE(prob, distance); szip/LzmaDec.c:189 - GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) szip/LzmaDec.c:264 - IF_BIT_0(probLen) szip/LzmaDec.c:201 - IF_BIT_0(prob) szip/LzmaDec.c:213 - IF_BIT_0(prob) szip/LzmaDec.c:290 - TREE_DECODE(probLen, limit, len); szip/LzmaDec.c:233 - IF_BIT_0(prob) No further analysis has been performed on the LZMA compression code. The vendor will remove this code entirely in future releases. Vulnerable / tested versions: ----------------------------- Versions before and including 6.10 / 6.1c22 of InfoZip's Unzip have been found to be vulnerable. Version 6.0 was the latest major release at the time the security vulnerabilities were discovered. The next beta version is 6.1c22 which has been tested as well. Vendor contact timeline: ------------------------ 2017-11-03: Vulnerability 1 identified, further internal analysis 2017-11-06: Attempt to contact the developers via bug report page 2017-11-10: Initial contact to the developer via [[email protected]](/cdn-cgi/l/email-protection) 2017-11-10: Information from the main developer: A new beta version (6.1c22), which will be released soon, incorporates some security features. A link to the new beta version was provided. 2017-11-12: Sending encrypted advisory to [[email protected]](/cdn-cgi/l/email-protection) Informed developer of the latest possible release date (2017-12-30). 2017-11-13: Developer confirms the vulnerability and notes that it should be easy to fix. The developer asks for a notification if vulnerabilities are found in version 6.1c22. 2017-11-21: Vulnerability 2-5 in UnZip 6.1c22 identified, the updated encrypted advisory with crash files was sent to the developer. 2017-11-23: Developer confirmed the e-mail containing the updated advisory. 2017-12-06: Asking the developer when an update will be available and to coordinate the release of the advisory together. 2017-12-11: E-mail from the developer: All vulnerabilities (except LZMA vulnerabilities) are fixed in version 6.1c23. A link to the new version was provided. The LZMA code / feature will likely be disabled until a better solution is available. 2017-12-13: Asking the developer for a coordinated release of the advisory. 2018-01-04: Informing the developer about the changed release date because of the holidays. Distribution mailing lists will be informed on 2018-01-17, the advisory will be released about one week after that. Asking the developer for an InfoZip version with LZMA disabled. 2018-01-10: Informing the developer again that the current solution is to upgrade to version 6.10c23 which still contains the LZMA vulnerabilities and if a version without LZMA is available. 2018-01-17: Informing [[email protected]](/cdn-cgi/l/email-protection) about the upcoming advisory. 2018-02-01: Received CVE numbers. 2018-02-07: Publication of the advisory Solution: --------- Update to version 6.10c23: Please note that the LZMA vulnerabilities are not yet fixed in this version. Workaround: ----------- None Advisory URL: ------------- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SEC Consult Vulnerability Lab SEC Consult Bangkok - Berlin - Linz - Luxembourg - Montreal - Moscow Kuala Lumpur - Singapore - Vienna (HQ) - Vilnius - Zurich About SEC Consult Vulnerability Lab The SEC Consult Vulnerability Lab is an integrated part of SEC Consult. It ensures the continued knowledge gain of SEC Consult in the field of network and application security to stay ahead of the attacker. The SEC Consult Vulnerability Lab supports high-quality penetration testing and the evaluation of new offensive and defensive technologies for our customers. Hence our customers obtain the most current information about vulnerabilities and valid recommendation about the risk profile of new technologies. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Interested to work with the experts of SEC Consult? Send us your application Interested in improving your cyber security with the experts of SEC Consult? Contact our local offices ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Mail: research at sec-consult dot com Web: Blog: Twitter: EOF R. Freingruber @2018


Log in to reply