Skip to content

ZIP Extraction Preserves SUID/SGID Bits, Allowing Local Privilege Escalation #1026

Description

@cryptcrack

Summary

When extracting a ZIP archive, mz_zip_reader_entry_save_file() (mz_zip_rw.c) applies the entry's Unix mode bits from external_fa directly via chmod() without masking S_ISUID, S_ISGID, or sticky bits. As a result, a crafted archive entry can cause the extracted file to be created with setuid (or setgid) permissions regardless of the extracting process's umask. If the archive is extracted by a privileged process, the resulting file may become a setuid-root binary that an unprivileged local user can execute to gain root privileges. This issue may lead to local privilege escalation.

Root Cause

  1. mz_zip_attrib_convert() (mz_zip.c) copies the Unix mode bits stored in external_fa verbatim (*target_attrib = src_attrib) when both the source and target host systems are Unix-like, without filtering special permission bits.
  2. mz_os_set_file_attribs() (mz_os_posix.c) passes the resulting mode directly to chmod(path, (mode_t)attributes).
  3. mz_zip_reader_entry_save_file() invokes both functions unconditionally for every extracted entry, with no option to disable this behavior via the minizip CLI.

Reproduction

Craft a ZIP archive containing an entry whose central directory record sets the version_madeby host-system byte to Unix and external_fa to (S_ISUID | 0755) << 16, using any ordinary relative entry name. Extract the archive with minizip -x -o -d <dest>. No special flags or destination are required, as this behavior occurs during every extraction. The extracted file will have mode 4755 regardless of the current umask.

PoC : evil.zip
Command:

  $ ./minizip -x -o -d ./dest ./evil.zip

Log

$ minizip -x -o -d /tmp/poc /tmp/evil.zip
minizip-ng 4.2.2 - https://github.com/zlib-ng/minizip-ng
---------------------------------------------------
-x -o -d /tmp/poc /tmp/evil.zip 
Archive /tmp/evil.zip
Extracting evil_setuid
$ ls -lah /tmp/poc
total 12K
drwxr-xr-x 2 root root 4.0K Jul 24 07:57 .
drwxrwxrwt 1 root root 4.0K Jul 24 07:57 ..
-rwsr-xr-x 1 root root   21 Nov 30  1979 evil_setuid
$ minizip -l /tmp/evil.zip
minizip-ng 4.2.2 - https://github.com/zlib-ng/minizip-ng
---------------------------------------------------
-l /tmp/evil.zip 
      Packed     Unpacked Ratio Method   Attribs Date     Time  CRC-32     Name
      ------     -------- ----- ------   ------- ----     ----  ------     ----
          21           21  100% stored   9ed0000 11-30-79 00:00 a4b6baa2   evil_setuid

Ref

tar option :
--no-same-owner
(x mode only) Do not extract owner and group IDs. This is the reverse of --same-owner and the default behavior if tar is run as non-root.
--no-same-permissions
(x mode only) Do not extract full permissions (SGID, SUID, sticky bit, file attributes or file flags, extended file attributes and ACLs). This is the reverse of -p and the default behavior if tar is run as non-root.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions