Lucene search
K

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

🗓️ 11 Apr 2016 00:00:00Reported by John LeitchType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 47 Views

Perl 5.22 VDir::MapPathA/W Out-of-bounds Reads and Buffer Over-reads. Vulnerabilities allowing arbitrary code execution due to out-of-bounds reads and buffer over-reads in VDir::MapPathA/W functions

Related
Code
`----------------------------------------------------------------  
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  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation