Perl 5.22 VDir::MapPathA/W Out-Of-Bounds Reads / Buffer Over-Reads

2016.04.12
Risk: High
Local: No
Remote: Yes
CWE: CWE-119


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

---------------------------------------------------------------- Name: Perl 5.22 VDir::MapPathA/W Out-of-bounds Reads and Buffer Over-reads Discovered By: John Leitch, Bryce Darling Url: http://autosectools.com/Perl-VDir-MapPath-Out-of-bounds-Read Report: https://rt.perl.org/Public/Bug/Display.html?id=126755 CVE-ID: CVE-2015-8608 Reported: November 28, 2015 Disclosed: January 11, 2016 ---------------------------------------------------------------- Perl 5.22 suffers from two out-of-bounds reads and multiple small buffer over-read vulnerabilities in the VDir::MapPathA and VDir::MapPathW functions that could potentially be exploited to achieve arbitrary code execution. The out-of-bounds read issues exist because the functions in question do not validate that the chr argument passed to DriveIndex, which calculates an index: inline int DriveIndex(char chr) { if (chr == '\\' || chr == '/') return ('Z'-'A')+1; return (chr | 0x20)-'a'; }; In the VDir::MapPathA function, DriveIndex is called with a potentially untrusted value, pInName, and the return value is then passed to GetDirA: char *VDir::MapPathA(const char *pInName) { /* * possiblities -- relative path or absolute path with or without drive letter * OR UNC name */ [...] if (pInName[1] == ':') { [...] } else { /* relative path with drive letter */ strcpy(szBuffer, GetDirA(DriveIndex(*pInName))); strcat(szBuffer, &pInName[2]); if(strlen(szBuffer) > MAX_PATH) szBuffer[MAX_PATH] = '\0'; DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA); } } else { [...] } return szLocalBufferA; } GetDirA then uses the unbounded index argument to index into dirTableA, a fixed length char pointer array. inline const char *GetDirA(int index) { char *ptr = dirTableA[index]; if (!ptr) { /* simulate the existence of this drive */ ptr = szLocalBufferA; ptr[0] = 'A' + index; ptr[1] = ':'; ptr[2] = '\\'; ptr[3] = 0; } return ptr; }; In cases where index is attacker controlled, this behavior can be used to read outside of the dirTableA array. This is especially problematic because the value returned is then copied to a fixed length buffer using strcpy: strcpy(szBuffer, GetDirA(DriveIndex(*pInName))); If an attacker can manipulate the layout of memory to trick GetDirA into returning a string larger than szBuffer, a buffer overflow will occur. The issue in VDir::MapPathW is nearly identical.. Further, multiple small and less critical buffer over-reads exist in both VDir::MapPathA and VDir::MapPathW: char *VDir::MapPathA(const char *pInName) { /* * possiblities -- relative path or absolute path with or without drive letter * OR UNC name */ [...] if (!length) <<< Check here confirms the buffer is at least of length 2 (including null) before continuing execution. return (char*)pInName; [...] if (pInName[1] == ':') { <<< While technically no over-read can occur here, pInName is a single character, this checks the null terminator. /* has drive letter */ if (IsPathSep(pInName[2])) { <<<< This could cause an over-read because the string could possibly be of length 2 (including null). /* absolute with drive letter */ DoGetFullPathNameA((char*)pInName, sizeof(szLocalBufferA), szLocalBufferA); } else { /* relative path with drive letter */ strcpy(szBuffer, GetDirA(DriveIndex(*pInName))); strcat(szBuffer, &pInName[2]); <<<< This could cause an over-read for the same reason. if(strlen(szBuffer) > MAX_PATH) szBuffer[MAX_PATH] = '\0'; DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA); } } else { [...] } } return szLocalBufferA; } To observe the out-of-bounds read vulnerability in VDir::MapPathA, the following script can be executed while Perl is under a debugger: print glob "]:"; Which will result in an exception similar to the following: (f78.1dd8): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=0081d62c ebx=0081dae2 ecx=765c7377 edx=7eff3920 esi=0081dae0 edi=0081d62c eip=747613a0 esp=0081d608 ebp=74744fac iopl=0 nv up ei pl nz na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206 MSVCR110!strcat+0x71: 747613a0 8a11 mov dl,byte ptr [ecx] ds:002b:765c7377=?? 0:000> k ChildEBP RetAddr 0081d608 709059ea MSVCR110!strcat+0x71 0081d940 7090688e perl523!VDir::MapPathA+0xdd 0081d94c 7090e295 perl523!PerlDirMapPathA+0x1f 0081dab4 70906736 perl523!win32_stat+0x6e 0081dac0 72541f60 perl523!PerlLIOLstat+0xd 0081dee4 7254181b Glob!g_lstat+0x72 0081df6c 725415e7 Glob!glob2+0x7a 0081efb0 72541141 Glob!glob0+0x181 0081f7cc 725420e8 Glob!bsd_glob+0x11d 0081f814 72542929 Glob!doglob+0x3f 0081f850 72542391 Glob!csh_glob+0x4a2 0081f894 708a05f4 Glob!iterate+0x1e8 0081f8ac 708cd3d8 perl523!Perl_pp_glob+0x19a 0081f8b8 70871fd8 perl523!Perl_runops_standard+0xc 0081f8cc 70871ef8 perl523!S_run_body+0xdf 0081f938 70908290 perl523!perl_run+0x1e6 0081fb68 00fe1216 perl523!RunPerl+0xbc 0081fba8 76de3744 perl!__tmainCRTStartup+0xfd 0081fbbc 77b7a064 KERNEL32!BaseThreadInitThunk+0x24 0081fc04 77b7a02f ntdll!__RtlUserThreadStart+0x2f 0081fc14 00000000 ntdll!_RtlUserThreadStart+0x1b To fix the issue, it is recommended that the VDir::MapPathA and VDir::MapPathW functions validate the drive letter to ensure no out-of-bounds reads occur, and also check the length of the pInName argument to ensure no buffer over-reads occur. A proposed patch is attached. However, the patch only addresses the issues in VDir::MapPathA because it was not immediately clear how to hit VDir::MapPathW for the purpose of testing. ---------------------------------------------------------------- Get ahead of the advanced persistent threats. http://autosectools.com/Consulting

References:

http://autosectools.com/Consulting


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