> -----Original Message-----
> From: pucik@xxxxxxxxxxx [mailto:pucik@xxxxxxxxxxx]
> Sent: Wednesday, August 09, 2006 7:18 PM
> To: full-disclosure@xxxxxxxxxxxxxxxxx; bugtraq@xxxxxxxxxxxxxxxxx
> Subject: [Overflow.pl] Clam AntiVirus Win32-UPX Heap Overflow
>
> Overflow.pl Security Advisory #6
>
> Clam AntiVirus Win32-UPX Heap Overflow
>
> Vendor: Clam AntiVirus
> Affected version: Prior to 0.88.4
> Vendor status: Fixed version released (0.88.4)
>
> Author: Damian Put <pucik@xxxxxxxxxxx>
> URL: http://www.overflow.pl/adv/clamav_upx_heap.txt
> Date: 09.08.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 a heap overflow vulnerability could
> allow execution of
> arbitrary code or cause denial of service.
>
> Vulnerability exists in pefromupx() function, that is used to buil
> Win32 PE file
> from UPX packed file.
>
> The vulnerable code is:
>
> libclamav/upx.c:
> ------------
> int pefromupx (char *src, char *dst, uint32_t *dsize,
> uint32_t ep, uint32_t
> upx0, uint32_t upx1, uint32_t magic)
> {
> char *imports, *sections, *pehdr, *newbuf;
> int sectcnt, upd=1;
> uint32_t realstuffsz;
> uint32_t foffset=0xd0+0xf8;
>
> imports = dst + cli_readint32(src + ep - upx1 + magic);
> realstuffsz = imports-dst;
>
> if (realstuffsz >= *dsize ) {
> cli_dbgmsg("UPX: wrong realstuff size - giving up rebuild\n");
> return 0;
> }
> ....
>
> OK first we check that realstuffsz is not larger than dsize.
>
> ....
> foffset+=0x28*sectcnt;
>
> if (!CLI_ISCONTAINED(dst, *dsize, sections, 0x28*sectcnt)) {
> cli_dbgmsg("UPX: Not enough space for all sects - giving
> up rebuild\n");
> return 0;
> }
> ....
>
> Now we check that we have enough space for section headers.
>
> ....
>
> for (upd = 0; upd <sectcnt ; upd++) {
> uint32_t vsize=cli_readint32(sections+8)-1;
> uint32_t rsize=cli_readint32(sections+16);
> uint32_t urva=cli_readint32(sections+12);
>
> .....
>
> cli_writeint32(sections+8, vsize);
> cli_writeint32(sections+20, foffset);
> foffset+=rsize;
> sections+=0x28;
> }
>
> ....
>
> Now, we add to foffset rsize value of all sections and we DON`T check
> that we have enough space in *dst.
>
> ....
>
> /* CBA restoring the imports they'll look different from
> the originals
> anyway... */
> /* ...and yeap i miss the icon too :P */
>
> memcpy(dst, newbuf, foffset);
> *dsize = foffset;
> free(newbuf);
>
> cli_dbgmsg("UPX: PE structure rebuilt from compressed file\n");
> return 1;
> }
>
> ....
>
> And there is our heap overflow. We copy from newbuf to dst
> pointer foffset
> bytes, but we don`t check that foffset > *dsize.
>
>
> 3. PoC
>
> The example of crafted upx file:
> http://overflow.pl/poc/clamav_upx_heap.exe
>
>
> [pucik@overflow UPX]$ clamscan clamav_upx_heap.exe
> *** glibc detected *** double free or corruption (out): 0x08bcbbc0 ***
> Przerwane (core dumped)
>
> You can control value of foffset changing "SizeOfRawData" of
> section 1.
>
>