Bug 12356 - ZIP bomb causes extreme CPU spikes
ZIP bomb causes extreme CPU spikes
Status: RESOLVED FIXED
Product: ClamAV
Classification: ClamAV
Component: clamdscan
stable
x86_64 GNU/Linux
: P3 security
: 0.102.0
Assigned To: Micah Snyder
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2019-07-04 15:31 EDT by Hanno Böck
Modified: 2021-11-02 13:46 EDT (History)
5 users (show)

See Also:
QA Contact:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Hanno Böck 2019-07-04 15:31:05 EDT
I wanted to point out [1], someone has used some tricks to create some extremely compressed ZIP files. I tested this on zblg.zip (10 MB that unpacks to 281 TB) and it causes extreme CPU spikes in clamscan and doesn't finish for several minutes (I stopped it at that point, no idea how long it'd run).

I think there needs to be some security limit in unpacking code, I'm pretty sure this can take down systems that use clamav for automated scanning.

[1] https://www.bamsoftware.com/hacks/zipbomb/
Comment 1 Micah Snyder 2019-07-05 12:37:10 EDT
Hi Hanno,

Thanks for the heads up.  Fun story - I tried to download the sample through Chrome, and the built-in scanner (ESET?) hung the download, while it presumably started to unzip.  A couple hours later, I had to force-quit Chrome because it was using up all of one processor, presumably still chewing on the zip-bomb.  Fun stuff.

I believe our unzip implementation is entirely custom, so unfortunately we can't just borrow the patch that Mark Adler wrote but will have to come up with a patch ourselves.

I did a little testing in a debugger and confirmed that it will extract and scan each "file" and that this will take a very very long time because each file takes quite a while to decompress and so will take a very long time to exceed the max # of files scanned. 

Micah
Comment 2 Hanno Böck 2019-07-09 06:18:07 EDT
Do you have any plan how to deal with this issue?

I'm wondering about disclosure. Given that this zip bomb got quite a bit of attention and it's really obvious to try to use this to DoS Antivirus scanners I'm not sure it's wise to try to keep this under the wraps for too long.

A temporary workaround is to disable archive unpacking of course.
Comment 3 Micah Snyder 2019-07-09 17:12:35 EDT
I've scheduled to sit down tomorrow with the guy who implemented the zip archive extractor for Snort3 to learn more, and discuss the issue.  So far we don't have a good plan for how to mitigate the zip bomb.  If you have any ideas, I'd love to hear it.
Comment 4 Micah Snyder 2019-07-12 14:23:51 EDT
I have a patch that records the size and offset of the previous file found in the zip when performing extraction using the central directory.  It compares these values with the current file to determine if the local file header data is overlapping.  If it is, it raises a heuristic alert, or if heuristic alerts are disabled, it simply returned a format error to prevent additional extraction.
We'll have to do a bit more testing to make sure the patch is solid, but I'm optimistic.

Our plan is to publish a very small 0.101.3 patch release with the fix as soon as we're able, while also publicly patching it in dev/0.102.
Comment 5 Micah Snyder 2019-08-01 16:11:04 EDT
Hi Hanno,

We're addressing this issue with this fix in 0.102 (beta coming very soon):
https://github.com/Cisco-Talos/clamav-devel/commit/23e0b6d35cc9beca0d768e8cf5f3769bbd5f9ef6

And will be addressing the issue with this fix in 0.101.3 (patch release coming very very soon):
https://github.com/Cisco-Talos/clamav-devel/commit/dcd26ea5f97bf851f4bac74f1367aedf5c162c9c

The 0.101.3 fix is logically the same as the 0.102 fix, but we cleaned up the code a bunch in 0.102 so the commits have different variable names and such.
Comment 7 Hanno Böck 2019-08-06 03:24:41 EDT
Created attachment 7572 [details]
overlap.zip
Comment 8 Hanno Böck 2019-08-06 03:25:13 EDT
Created attachment 7573 [details]
spaced.zip
Comment 9 Hanno Böck 2019-08-06 03:26:14 EDT
Can confirm that there are still issues. I've attached both examples created based on David's instructions.
Comment 10 Micah Snyder 2019-08-09 11:59:22 EDT
To address the remaining issue raised by David Fifield, we're investigating adding a scan timeout (--max-scantime / MaxScanTime) to mitigate the trouble caused by excessively long scan times.  

The code for the max scan time is complete as of yesterday, and just needs regression testing and review. 

We will do our best to get 0.101.4 ready/published with this change and one or two others in the coming weeks.
Comment 11 Sebastian A. Siewior 2019-08-09 17:03:59 EDT
(In reply to Micah Snyder from comment #10)
> To address the remaining issue raised by David Fifield, we're investigating
> adding a scan timeout (--max-scantime / MaxScanTime) to mitigate the trouble
> caused by excessively long scan times.  
> 
> The code for the max scan time is complete as of yesterday, and just needs
> regression testing and review. 
> 
> We will do our best to get 0.101.4 ready/published with this change and one
> or two others in the coming weeks.

I would prefer something where the "recursive" part recognized or extreme high compression ration is detected and flagged as such instead solving it via a timeout. This can lead to false positives especially on high-loaded/ slow servers.

Sebastian
Comment 12 Micah Snyder 2019-08-10 18:32:57 EDT
(In reply to Sebastian A. Siewior from comment #11)
> (In reply to Micah Snyder from comment #10)
> > To address the remaining issue raised by David Fifield, we're investigating
> > adding a scan timeout (--max-scantime / MaxScanTime) to mitigate the trouble
> > caused by excessively long scan times.  
> > 
> > The code for the max scan time is complete as of yesterday, and just needs
> > regression testing and review. 
> > 
> > We will do our best to get 0.101.4 ready/published with this change and one
> > or two others in the coming weeks.
> 
> I would prefer something where the "recursive" part recognized or extreme
> high compression ration is detected and flagged as such instead solving it
> via a timeout. This can lead to false positives especially on high-loaded/
> slow servers.
> 
> Sebastian

The issue is that this zip bomb type is non-recursive, so our recursion limit doesn't halt zip extraction.  

We also have a max number of files (default 10,000) but getting there with zip file extraction and scanning takes a _very_ long time.  

The scan-size maximum won't affect it because the intention if a file would exceed max scan size is to skip it, avoid exceeding the maximum, with the hope of finding and scanning smaller fixes (i.e. doesn't halt zip extraction).

Limiting of scan time (with a relatively high default and the option to configure it as needed is the most robust option.  David Fifield also suggested we could pre-sort the list of files in the zip by file offset, and while this would solve the immediate issue, it would be fairly complex to implement in our current unzip code.

A big benefit of adding a scan time limit is that it will also help mitigate scan time issues for other file types in the future so performance issues don't end up requiring CVEs.
Comment 13 Sebastian A. Siewior 2019-08-11 08:03:28 EDT
(In reply to Micah Snyder from comment #12)
> The issue is that this zip bomb type is non-recursive, so our recursion
> limit doesn't halt zip extraction.  

as far as I understand, the file references the "kernel" block multiple times. Is this a standard behavior that a compressor may use or is this something that has been used to create that? The `unzip' package uses this (using an already covered block) to detect a zip bomb:
  https://sources.debian.org/src/unzip/6.0-25/debian/patches/23-cve-2019-13232-zip-bomb-with-overlapped-entries.patch/

It takes a few seconds to detect it but works for both files:
|$ unzip -t spaced.zip 
|Archive:  spaced.zip
|    testing: 0                        OK
|    testing: spacer0                  OK
|error: invalid zip file with overlapped components (possible zip bomb)

> We also have a max number of files (default 10,000) but getting there with
> zip file extraction and scanning takes a _very_ long time.  

testing for spacer0 is already taking approx 10 secs here so yes, I get that.

> The scan-size maximum won't affect it because the intention if a file would
> exceed max scan size is to skip it, avoid exceeding the maximum, with the
> hope of finding and scanning smaller fixes (i.e. doesn't halt zip
> extraction).
>
> Limiting of scan time (with a relatively high default and the option to
> configure it as needed is the most robust option.  David Fifield also
> suggested we could pre-sort the list of files in the zip by file offset, and
> while this would solve the immediate issue, it would be fairly complex to
> implement in our current unzip code.
> 
> A big benefit of adding a scan time limit is that it will also help mitigate
> scan time issues for other file types in the future so performance issues
> don't end up requiring CVEs.

As long as the extraction process does not create any temporary files or allocates memory since writting 10GiB to disk before noticing a possible trick is already bad.

Btw: Can we please move the status back from RESOLVED to OPEN or so since the second files (here attached) lets it still explode.

Sebastian
Comment 14 Micah Snyder 2019-08-15 14:30:16 EDT
This is the commit to address the zip-bomb scan-time issue in 0.101.4:
https://github.com/Cisco-Talos/clamav-devel/commit/0359cc5754403f4643db6cfc9267823f84d57f5a

When we merge the equivalent commit for dev/0.102, I'll post it here as well.

The goal is really to eliminate the possibility of excessive scan time from clobbering libclamav/clamd/clamscan. As far as that is concerned this will complete the mitigation for the zip bomb issue.

This zip bomb issue as it relates to ClamAV as a resource utilization vulnerability has been assigned CVE identifier CVE-2019-12625.  

Because the patch for 0.101.3 did not completely address the issue, as pointed out by David Fifield, we'll be stating that ClamAV versions 0.101.3 and prior are vulnerable to CVE-2019-12625.  I.e. we're not creating two different CVE's.
Comment 15 Micah Snyder 2019-08-30 15:43:34 EDT
This is the scan time limit commit for 0.102: https://github.com/Cisco-Talos/clamav-devel/commit/b056e8e4b505ff1f4c2c0ad31e1046e58a9f0e57
Comment 16 Micah Snyder 2020-08-19 20:45:15 EDT
Forgot to close this earlier.
Comment 17 Ahmed Sayeed 2021-11-02 13:46:01 EDT
#0  0x000055befa524260 in execute_cfa_program (fde=0x621000f84c90, http://www-look-4.com/technology/peugeot-208/ insn_ptr=0x7fab8d86da86 <error: Cannot access memory at address 0x7fab8d86da86>, http://the-hunters.org/category/tech/ insn_end=0x7fab8d86da90 <error: Cannot access memory at address 0x7fab8d86da90>, gdbarch=0x621000be3d10, https://komiya-dental.com/computers/huawei-technology/ pc=0xffffffff81b3318e, fs=0x7ffe0a288d10, text_offset=0x0) at /home/smarchi/src/binutils-gdb/gdb/dwarf2/frame.c:367 http://www.iu-bloomington.com/crypto/china-affect-on-crypto/ 
#1  0x000055befa52bf02 in dwarf2_frame_cache (this_frame=0x6210006cfde0, this_cache=0x6210006cfdf8) https://waytowhatsnext.com/crypto/cryptocurrency-taxes/ at /home/smarchi/src/binutils-gdb/gdb/dwarf2/frame.c:1025
#2  0x00 http://fishingnewsletters.co.uk/category/property/ 0055befa52ea38 in dwarf2_frame_this_id (this_frame=0x6210006cfde0, http://www.wearelondonmade.com/services/car-repair-services/  this_cache=0x6210006cfdf8, this_id=0x6210006cfe40) at /home/smarchi/src/binutils-gdb/gdb/dwarf2/frame.c:1226 http://www.jopspeech.com/property/slim-pen-2/
#3  0x000055befa8dde95 in compute_frame_id (fi=0x6210006cfde0) at /home/smarchi/src/binutils-gdb/gdb/frame.c:588 http://joerg.li/tech/cars-comparison/
#4  0x000055befa8de53e in get_frame_id (fi=0x6210006cfde0) at /home/smarchi/src/binutils-gdb/gdb/frame.c:636 http://connstr.net/tech/mars-surface/
#5  0x000055befa8ecf33 in get_prev_frame (this_frame=0x6210006cfde0) http://www.go-mk-websites.co.uk/category/property/ at /home/smarchi/src/binutils-gdb/gdb/frame.c:2504 http://embermanchester.uk/property/chat-themes/
#6  0x000055befb1ff582 in frame_info_to_frame_object (frame=0x6210006cfde0) http://www.mconstantine.co.uk/category/property/ at /home/smarchi/src/binutils-gdb/gdb/python/py-frame.c:364 http://www.slipstone.co.uk/computers/isofix/ 
#7  0x000055befb201016 in gdbpy_newest_frame (self=0x7fabbcb11a40, args=0x0) at /home/smarchi/src/binutils-gdb/gdb/python/py-frame.c:599
#8  0x00007fabc25f01aa in cfunction_vectorcall_NOARGS (func=0x7fabbca78d60, args=<optimized out>, nargsf=<optimized out>, kwnames=<optimized out>) at ../Objects/methodobject.c:459 http://www.logoarts.co.uk/tech/drone-cameras/
#9  0x00007fabc2405d6d in _PyObject_Vectorcall (kwnames=<optimized out>, nargsf=<optimized out>, args=<optimized out>, callable=<optimized out>) at ../Include/cpython/abstract.h:127 http://www.acpirateradio.co.uk/property/applications/ 
#10 call_function (tstate=0x612000009940, pp_stack=0x7ffe0a289370, oparg=<optimized out>, kwnames=0x0) at ../Python/ceval.c:4963 http://www.compilatori.com/health/premium-subscription/
#11 0x00007fabc240def6 in _PyEval_EvalFrameDefault (f=<optimized out>, throwflag=<optimized out>) at ../Python/ceval.c:3469 https://www.webb-dev.co.uk/shopping/shopping-during-corona/ 
#12 0x00007fabc241106b in function_code_fastcall (co=<optimized out>, args=<optimized out>, nargs=1, globals=<optimized out>) at ../Objects/call.c:283