all things security

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

Perl 5.22 VDir::MapPathA/W Out-Of-Bounds Reads / Buffer Over-Reads
Posted Apr 11, 2016
Authored by John Leitch

Perl version 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.

tags | exploit, arbitrary, perl, vulnerability, code execution
advisories | CVE-2015-8608
MD5 | 7bd4f274aa06f06b50d992e05391c4ad

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

Change Mirror Download
----------------------------------------------------------------
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

Comments

RSS Feed Subscribe to this comment feed

No comments yet, be the first!

Login or Register to post a comment

File Archive:

October 2017

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Oct 1st
    15 Files
  • 2
    Oct 2nd
    16 Files
  • 3
    Oct 3rd
    15 Files
  • 4
    Oct 4th
    15 Files
  • 5
    Oct 5th
    11 Files
  • 6
    Oct 6th
    6 Files
  • 7
    Oct 7th
    2 Files
  • 8
    Oct 8th
    1 Files
  • 9
    Oct 9th
    13 Files
  • 10
    Oct 10th
    16 Files
  • 11
    Oct 11th
    15 Files
  • 12
    Oct 12th
    23 Files
  • 13
    Oct 13th
    13 Files
  • 14
    Oct 14th
    12 Files
  • 15
    Oct 15th
    2 Files
  • 16
    Oct 16th
    16 Files
  • 17
    Oct 17th
    2 Files
  • 18
    Oct 18th
    0 Files
  • 19
    Oct 19th
    0 Files
  • 20
    Oct 20th
    0 Files
  • 21
    Oct 21st
    0 Files
  • 22
    Oct 22nd
    0 Files
  • 23
    Oct 23rd
    0 Files
  • 24
    Oct 24th
    0 Files
  • 25
    Oct 25th
    0 Files
  • 26
    Oct 26th
    0 Files
  • 27
    Oct 27th
    0 Files
  • 28
    Oct 28th
    0 Files
  • 29
    Oct 29th
    0 Files
  • 30
    Oct 30th
    0 Files
  • 31
    Oct 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2016 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close