ClamAV heap buffer overflow scanning a specially crafted file

2014.11.22
Credit: Damien
Risk: High
Local: No
Remote: Yes
CWE: N/A


CVSS Base Score: 5/10
Impact Subscore: 2.9/10
Exploitability Subscore: 10/10
Exploit range: Remote
Attack complexity: Low
Authentication: No required
Confidentiality impact: None
Integrity impact: None
Availability impact: Partial

A heap buffer overflow was reported in [1] in ClamAV when scanning a specially crafted y0da Crypter obfuscated PE file. Note that this is remotely exploitable when ClamAV is used as a mail gateway scanner. Upstream fix is available here: [2]. ClamAV 0.98.5 contains the above fix. Additional references: [1] https://bugzilla.clamav.net/show_bug.cgi?id=11155 [2] https://github.com/vrtadmin/clamav-devel/commit/fc3794a54d2affe5770c1f876484a871c783e91e ibclamav/pe.c View @@ -737,14 +737,14 @@ int cli_scanpe(cli_ctx *ctx) char sname[9], epbuff[4096], *tempfile; uint32_t epsize; ssize_t bytes, at; - unsigned int i, found, upx_success = 0, min = 0, max = 0, err, overlays = 0; + unsigned int i, j, found, upx_success = 0, min = 0, max = 0, err, overlays = 0, rescan = 1; unsigned int ssize = 0, dsize = 0, dll = 0, pe_plus = 0, corrupted_cur; int (*upxfn)(const char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t) = NULL; const char *src = NULL; char *dest = NULL; int ndesc, ret = CL_CLEAN, upack = 0, native=0; size_t fsize; - uint32_t valign, falign, hdr_size, j; + uint32_t valign, falign, hdr_size; struct cli_exe_section *exe_sections; char timestr[32]; struct pe_image_data_dir *dirs; @@ -1238,18 +1238,52 @@ int cli_scanpe(cli_ctx *ctx) cli_jsonint(pe_json, "NumberOfSections", nsections); #endif + while (rescan==1) { + rescan=0; + for (i=0; i < nsections; i++) { + exe_sections[i].rva = PEALIGN(EC32(section_hdr[i].VirtualAddress), valign); + exe_sections[i].vsz = PESALIGN(EC32(section_hdr[i].VirtualSize), valign); + exe_sections[i].raw = PEALIGN(EC32(section_hdr[i].PointerToRawData), falign); + exe_sections[i].rsz = PESALIGN(EC32(section_hdr[i].SizeOfRawData), falign); + exe_sections[i].chr = EC32(section_hdr[i].Characteristics); + exe_sections[i].urva = EC32(section_hdr[i].VirtualAddress); /* Just in case */ + exe_sections[i].uvsz = EC32(section_hdr[i].VirtualSize); + exe_sections[i].uraw = EC32(section_hdr[i].PointerToRawData); + exe_sections[i].ursz = EC32(section_hdr[i].SizeOfRawData); + + if (exe_sections[i].rsz) { /* Don't bother with virtual only sections */ + if (!CLI_ISCONTAINED(0, fsize, exe_sections[i].uraw, exe_sections[i].ursz) + || exe_sections[i].raw >= fsize) { + cli_dbgmsg("Broken PE file - Section %d starts or exists beyond the end of file (Offset@ %lu, Total filesize %lu)\n", i, (unsigned long)exe_sections[i].raw, (unsigned long)fsize); + if (nsections == 1) { + free(section_hdr); + free(exe_sections); + + if(DETECT_BROKEN_PE) { + cli_append_virus(ctx, "Heuristics.Broken.Executable"); + return CL_VIRUS; + } + + return CL_CLEAN; /* no ninjas to see here! move along! */ + } + + for (j=i; j < nsections-1; j++) + memcpy(&exe_sections[j], &exe_sections[j+1], sizeof(struct cli_exe_section)); + + for (j=i; j < nsections-1; j++) + memcpy(&section_hdr[j], &section_hdr[j+1], sizeof(struct pe_image_section_hdr)); + + nsections--; + rescan=1; + break; + } + } + } + } + for(i = 0; i < nsections; i++) { - strncpy(sname, (char *) section_hdr[i].Name, 8); - sname[8] = 0; - exe_sections[i].rva = PEALIGN(EC32(section_hdr[i].VirtualAddress), valign); - exe_sections[i].vsz = PESALIGN(EC32(section_hdr[i].VirtualSize), valign); - exe_sections[i].raw = PEALIGN(EC32(section_hdr[i].PointerToRawData), falign); - exe_sections[i].rsz = PESALIGN(EC32(section_hdr[i].SizeOfRawData), falign); - exe_sections[i].chr = EC32(section_hdr[i].Characteristics); - exe_sections[i].urva = EC32(section_hdr[i].VirtualAddress); /* Just in case */ - exe_sections[i].uvsz = EC32(section_hdr[i].VirtualSize); - exe_sections[i].uraw = EC32(section_hdr[i].PointerToRawData); - exe_sections[i].ursz = EC32(section_hdr[i].SizeOfRawData); + strncpy(sname, (char *) section_hdr[i].Name, 8); + sname[8] = 0; #if HAVE_JSON add_section_info(ctx, &exe_sections[i]); @@ -1304,18 +1338,6 @@ int cli_scanpe(cli_ctx *ctx) } if (exe_sections[i].rsz) { /* Don't bother with virtual only sections */ - if (exe_sections[i].raw >= fsize) { /* really broken */ - cli_dbgmsg("Broken PE file - Section %d starts beyond the end of file (Offset@ %lu, Total filesize %lu)\n", i, (unsigned long)exe_sections[i].raw, (unsigned long)fsize); - cli_dbgmsg("------------------------------------\n"); - free(section_hdr); - free(exe_sections); - if(DETECT_BROKEN_PE) { - cli_append_virus(ctx, "Heuristics.Broken.Executable"); - return CL_VIRUS; - } - return CL_CLEAN; /* no ninjas to see here! move along! */ - } - if(SCAN_ALGO && (DCONF & PE_CONF_POLIPOS) && !*sname && exe_sections[i].vsz > 40000 && exe_sections[i].vsz < 70000 && exe_sections[i].chr == 0xe0000060) polipos = i; /* check hash section sigs */

References:

https://bugzilla.clamav.net/show_bug.cgi?id=11155
https://github.com/vrtadmin/clamav-devel/commit/fc3794a54d2affe5770c1f876484a871c783e91e


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2024, cxsecurity.com

 

Back to Top