ckolivas / lrzip

Long Range Zip
http://lrzip.kolivas.org
GNU General Public License v2.0
618 stars 76 forks source link

heap-buffer-overflow in libzpaq/libzpaq.cpp:1208:25 libzpaq::PostProcessor::write(int) #246

Open huanglei3 opened 1 year ago

huanglei3 commented 1 year ago

project : lrzip 0.651

exec : ./lrzip -t file

Decompressing...

==641214==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6140000001ec at pc 0x0000005260ac bp 0x7f4b526e35d0 sp 0x7f4b526e35c8 WRITE of size 1 at 0x6140000001ec thread T2

0 0x5260ab in libzpaq::PostProcessor::write(int) /home/cc/lrzip/obj-afl/../libzpaq/libzpaq.cpp:1208:25

#1 0x526fe1 in libzpaq::Decompresser::decompress(int) /home/cc/lrzip/obj-afl/../libzpaq/libzpaq.cpp:1311:8
#2 0x507a9e in libzpaq::decompress(libzpaq::Reader*, libzpaq::Writer*) /home/cc/lrzip/obj-afl/../libzpaq/libzpaq.cpp:1366:9
#3 0x5075f4 in zpaq_decompress /home/cc/lrzip/obj-afl/../libzpaq/libzpaq.h:539:2
#4 0x4f6d52 in zpaq_decompress_buf /home/cc/lrzip/obj-afl/../stream.c:446:2
#5 0x4f6d52 in ucompthread /home/cc/lrzip/obj-afl/../stream.c:1566:11
#6 0x7f4b55f21608 in start_thread /build/glibc-SzIz7B/glibc-2.31/nptl/pthread_create.c:477:8
#7 0x7f4b55c37132 in clone /build/glibc-SzIz7B/glibc-2.31/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:95

0x6140000001ec is located 0 bytes to the right of 428-byte region [0x614000000040,0x6140000001ec) allocated by thread T2 here:

0 0x495f42 in calloc (/home/cc/lrzip/obj-afl/lrzip+0x495f42)

#1 0x525692 in libzpaq::calloc(unsigned long, unsigned long) /home/cc/lrzip/obj-afl/../libzpaq/libzpaq.cpp:34:42
#2 0x525692 in libzpaq::Array<unsigned char>::resize(unsigned long, int) /home/cc/lrzip/obj-afl/../libzpaq/libzpaq.h:114:12
#3 0x525692 in libzpaq::PostProcessor::write(int) /home/cc/lrzip/obj-afl/../libzpaq/libzpaq.cpp:1198:16

Thread T2 created by T0 here:

0 0x480b7a in pthread_create (/home/cc/lrzip/obj-afl/lrzip+0x480b7a)

#1 0x4ee31f in create_pthread /home/cc/lrzip/obj-afl/../stream.c:125:6
#2 0x4ee31f in fill_buffer /home/cc/lrzip/obj-afl/../stream.c:1725:6
#3 0x4ee31f in read_stream /home/cc/lrzip/obj-afl/../stream.c:1812:8
#4 0x4e3ce0 in unzip_literal /home/cc/lrzip/obj-afl/../runzip.c:162:16
#5 0x4e3ce0 in runzip_chunk /home/cc/lrzip/obj-afl/../runzip.c:325:9
#6 0x4e3ce0 in runzip_fd /home/cc/lrzip/obj-afl/../runzip.c:387:7
#7 0x4d1e61 in decompress_file /home/cc/lrzip/obj-afl/../lrzip.c:951:6
#8 0x4ca86a in main /home/cc/lrzip/obj-afl/../main.c:720:4
#9 0x7f4b55b3c082 in __libc_start_main /build/glibc-SzIz7B/glibc-2.31/csu/../csu/libc-start.c:308:16

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/cc/lrzip/obj-afl/../libzpaq/libzpaq.cpp:1208:25 in libzpaq::PostProcessor::write(int) Shadow bytes around the buggy address: 0x0c287fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c287fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c287fff8000: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00 0x0c287fff8010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c287fff8020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0c287fff8030: 00 00 00 00 00 00 00 00 00 00 00 00 00[04]fa fa 0x0c287fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c287fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c287fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c287fff8070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c287fff8080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb Shadow gap: cc ==641214==ABORTING poc.zip

and you can download it from the link: poc:https://github.com/huanglei3/lrzip_poc/blob/main/lrzip_heap_overflow/overflow

pete4abw commented 1 year ago

Try this for lrzip:

diff --git a/stream.c b/stream.c
index 7093ca9..87597c4 100644
--- a/stream.c
+++ b/stream.c
@@ -1220,11 +1220,11 @@ again:
                                print_err("Wrong password?\n");
                        goto failed;
                }
-               if (unlikely(v1)) {
+               if (unlikely(v1 < 1)) {
                        print_err("Unexpected initial c_len %lld in streams %lld\n", v1, v2);
                        goto failed;
                }
-               if (unlikely(v2)) {
+               if (unlikely(v2 < 1)) {
                        print_err("Unexpected initial u_len %lld in streams\n", v2);
                        goto failed;
                }
carnil commented 1 year ago

This issue seems to be CVE-2023-39741

pete4abw commented 1 year ago

@carnil , The actual bug is in ZPAQ. The SDK used here is old. The last SDK (before Matt Mahoney retired), 7.15 has more robust error checking. Using @huanglei3 POC file...

There's a limit to how much error prevention can be done. If you examine the code in stream.c and other files, you will see exhaustive data checks. a solution is either to update the zpaq SDK like I did with lrzip-next or examine the libzpaq.cpp file at line 1311 and 1208. Or you can try the preventative fix posted above.

I get tired of these attempts to make a program fail. I'd rather people would try and make the programs better. Contribute code.

Fill_buffer stream 1 c_len 981 u_len 6036 last_head 1019
Starting thread 1 to decompress 981 bytes from stream 1
Reading ucomp header at 1048
Fill_buffer stream 1 c_len 0 u_len 0 last_head 0
Skipping empty match block
                        ZPAQ            2:21%  
Thread 3 "lrzip" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff7a1e6c0 (LWP 8576)]
libzpaq::PostProcessor::write (this=0x7ffff7a1dc70, c=0) at libzpaq/libzpaq.cpp:1208
1208          z.header[z.hend++]=c;  // one byte of pcomp
(gdb) info stack
#0  libzpaq::PostProcessor::write (this=0x7ffff7a1dc70, c=0) at libzpaq/libzpaq.cpp:1208
#1  0x0000555555582ce4 in libzpaq::Decompresser::decompress (this=0x7ffff7a02b60, n=-1) at libzpaq/libzpaq.cpp:1311
#2  0x0000555555582f15 in libzpaq::decompress (in=0x7ffff7a1ddc0, out=0x7ffff7a1dda0) at libzpaq/libzpaq.cpp:1366
#3  0x000055555557a729 in zpaq_decompress (s_buf=0x7ffff0000b70 "", d_len=0x7ffff7a1de68, c_buf=0x5555555ca160 "zPQ\001", <incomplete sequence \304>, c_len=697, msgout=0x7ffff7bf2760 <_IO_2_1_stdout_>, progress=true, 
    thread=1) at libzpaq/libzpaq.h:539
#4  0x000055555556d063 in zpaq_decompress_buf (control=0x5555555aed40 <local_control>, ucthread=0x5555555c85e0, thread=1) at stream.c:446
#5  0x000055555557190e in ucompthread (data=0x0) at stream.c:1566
#6  0x00007ffff7aa8044 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#7  0x00007ffff7b285fc in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

Using SDK 7.15 from lrzip-next

Fill_buffer stream 1 c_len 0 u_len 0 last_head 0
Skipping empty match block
ZPAQ Error: Empty PCOMP
[Inferior 1 (process 13034) exited with code 01]