Overflow.pl Security Advisory #5 Clam AntiVirus Win32-UPX Heap Overflow (not default configuration) Vendor: Clam AntiVirus Affected version: Prior to 0.88.1 Vendor status: Fixed version released (0.88.1) Author: Damian Put URL: http://www.overflow.pl/adv/clamavupxinteger.txt Date: 5.04.2006 1. Background "Clam AntiVirus is a GPL anti-virus toolkit for UNIX. The main purpose of this software is the integration with mail servers (attachment scanning). The package provides a flexible and scalable multi-threaded daemon, a command line scanner, and a tool for automatic updating via Internet. The programs are based on a shared library distributed with the Clam AntiVirus package, which you can use with your own software. Most importantly, the virus database is kept up to date" http://www.clamav.net 2. Description Remote exploitation of an integer overflow vulnerability could allow execution of arbitrary code or cause denial of service. An integer overflow leading to heap overflow, exists in cli_scanpe() function, that is used to read Win32 files. The vulnerable code is: libclamav/pe.c: .... if((dest = (char *) cli_calloc(dsize + 1024 + nsections * 40, sizeof(char))) == NULL) { free(section_hdr); free(src); return CL_EMEM; } ... Before cli_calloc call, we should check that "dsize + 1024 + nsections * 40" not overflow integer variable. We can control value of "dsize" and "nsections" variables, so exploitation of this vulnerability is possible, with special crafted file. Unfortunately, "dsize" cannot be larger than ArchiveMaxFileSize, so this bug doesn`t apply to default configuration of ClamAv Next, "dest" is used in upx_inflate() function, if section is compressed with UPX: libclamav/upx.c: ... int upx_inflate2d(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep) { int32_t backbytes, unp_offset = -1, myebx = 0; int scur=0, dcur=0, i, backsize, oob; while (1) { while ( (oob = doubleebx(src, &myebx, &scur, ssize)) == 1) { if (scur<0 || scur>=ssize || dcur<0 || dcur>=*dsize) return -1; dst[dcur++] = src[scur++]; } ... backsize++; for (i = 0; i < backsize; i++) { if (dcur+i<0 || dcur+i>=*dsize || dcur+unp_offset+i<0 || dcur+unp_offset+i>=*dsize) return -1; dst[dcur + i] = dst[dcur + unp_offset + i]; } dcur+=backsize; } .... If we don't allocate enough memory to "dst", these loops will overflow a heap. 3. PoC The example of crafted upx file: http://overflow.pl/poc/crafted_upx.exe [pucik@overflow clam]$ clamscan --debug --max-space=0 crafted_upx.exe .... LibClamAV debug: EntryPoint offset: 0x2bee0 (179936) LibClamAV debug: UPX/FSG: empty section found - assuming compression LibClamAV debug: UPX: Section 0 name: UPX0 LibClamAV debug: UPX: Section 1 name: UPX1 //This is my debug LibClamAV debug: UPX: dsize = -1024, nsections = 3, dsize + 1024 + nsections * 40 = 120 LibClamAV debug: UPX: Looks like a NRV2D decompression routine Segmentation fault (core dumped)