Project: php-src (php/php-src), language: c++
Vulnerability instance: php.cve-2019-9020
Sanitizer: address

================= Bug Report (1/2) ==================
## Source: PHP Bugs
## URL: https://bugs.php.net/bug.php?id=77242
## Description:
PHP Bug ID: 77242
Summary: heap out of bounds read in xmlrpc_decode()
Status: Closed
PHP Version: 5.6.39
Assigned: stas (profile)
CVE-ID: 2019-9020

Description:
Description:
------------
Invalid input to the function xmlrpc_decode() can lead to an invalid memory access (heap out of bounds read).

To see this php needs to be compiled with address sanitizer and USE_ZEND_ALLOC=0 needs to be set, otherwise PHP's memory allocator will hide the bug.


Test script:
---------------
$a=xmlrpc_decode(base64_decode("PD94bWwgdmVyc2lvbmVuY29kaW5nPSJJU084ODU5NyKkpKSkpKSkpKSkpKSkpKSkpKSkpKSk"));

Expected result:
----------------
No memory safety violations.

Actual result:
--------------
Address Sanitizer reports an error:

==27114==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60b00008d528 at pc 0x000000439739 bp 0x7fffb217fad0 sp 0x7fffb217f278
READ of size 25 at 0x60b00008d528 thread T0
    #0 0x439738 in __interceptor_strlen (/r/php/php+0x439738)
    #1 0x1614386 in format_converter /f/php/php-7.2.12/main/snprintf.c:997:15
    #2 0x1614386 in strx_printv /f/php/php-7.2.12/main/snprintf.c:1252
    #3 0x16104af in ap_php_snprintf /f/php/php-7.2.12/main/snprintf.c:1297:2
    #4 0x15e19ab in xml_elem_parse_buf /f/php/php-7.2.12/ext/xmlrpc/libxmlrpc/xml_element.c:724:14
    #5 0x15e3830 in XMLRPC_REQUEST_FromXML /f/php/php-7.2.12/ext/xmlrpc/libxmlrpc/xmlrpc.c:808:3
    #6 0x15c4f7b in decode_request_worker /f/php/php-7.2.12/ext/xmlrpc/xmlrpc-epi-php.c:763:13
    #7 0x15c4f7b in zif_xmlrpc_decode /f/php/php-7.2.12/ext/xmlrpc/xmlrpc-epi-php.c:818
    #8 0x1bc7c08 in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER /f/php/php-7.2.12/Zend/zend_vm_execute.h:617:2
    #9 0x1980f8c in execute_ex /f/php/php-7.2.12/Zend/zend_vm_execute.h:59739:7
    #10 0x1981875 in zend_execute /f/php/php-7.2.12/Zend/zend_vm_execute.h:63776:2
    #11 0x17be1d1 in zend_eval_stringl /f/php/php-7.2.12/Zend/zend_execute_API.c:1083:4
    #12 0x17beb0f in zend_eval_stringl_ex /f/php/php-7.2.12/Zend/zend_execute_API.c:1124:11
    #13 0x17beb0f in zend_eval_string_ex /f/php/php-7.2.12/Zend/zend_execute_API.c:1135
    #14 0x1d01706 in do_cli /f/php/php-7.2.12/sapi/cli/php_cli.c:1044:8
    #15 0x1cfee22 in main /f/php/php-7.2.12/sapi/cli/php_cli.c:1407:18
    #16 0x7f659b60c4ea in __libc_start_main (/lib64/libc.so.6+0x244ea)
    #17 0x423dc9 in _start (/r/php/php+0x423dc9)

0x60b00008d528 is located 0 bytes to the right of 104-byte region [0x60b00008d4c0,0x60b00008d528)
allocated by thread T0 here:
    #0 0x4ce2b3 in __interceptor_malloc (/r/php/php+0x4ce2b3)
    #1 0x172646f in __zend_malloc /f/php/php-7.2.12/Zend/zend_alloc.c:2829:14
    #2 0x1724cdd in _emalloc /f/php/php-7.2.12/Zend/zend_alloc.c:2429:11
    #3 0x13d51d5 in zend_string_alloc /f/php/php-7.2.12/Zend/zend_string.h:134:36
    #4 0x13d51d5 in php_base64_decode_ex /f/php/php-7.2.12/ext/standard/base64.c:136
    #5 0x13d6282 in zif_base64_decode /f/php/php-7.2.12/ext/standard/base64.c:238:11
    #6 0x1bc7c08 in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER /f/php/php-7.2.12/Zend/zend_vm_execute.h:617:2
    #7 0x1980f8c in execute_ex /f/php/php-7.2.12/Zend/zend_vm_execute.h:59739:7
    #8 0x1981875 in zend_execute /f/php/php-7.2.12/Zend/zend_vm_execute.h:63776:2
    #9 0x17be1d1 in zend_eval_stringl /f/php/php-7.2.12/Zend/zend_execute_API.c:1083:4
    #10 0x17beb0f in zend_eval_stringl_ex /f/php/php-7.2.12/Zend/zend_execute_API.c:1124:11
    #11 0x17beb0f in zend_eval_string_ex /f/php/php-7.2.12/Zend/zend_execute_API.c:1135
    #12 0x1d01706 in do_cli /f/php/php-7.2.12/sapi/cli/php_cli.c:1044:8
    #13 0x1cfee22 in main /f/php/php-7.2.12/sapi/cli/php_cli.c:1407:18
    #14 0x7f659b60c4ea in __libc_start_main (/lib64/libc.so.6+0x244ea)
    #15 0x423dc9 in _start (/r/php/php+0x423dc9)

Comments:

[Comment 1] [2018-12-08 17:53 UTC] cmb@php.net
Thanks for reporting this issue!

We're basically hitting bug #52998 here[1]: byte_idx is 66,
although len is only 54.  Wrt. our bundled libxmlrpc the solution
is simple: just remove the sprintf(buf, …), since buf is not used
anymore in the following since commit 780ff63[2].

I'm not sure whether upstream libxmlrpc-epi[3] is affected by
this, since it likely does not work with libxml2 but rather with
libexpat only.

Anyhow, a general patch might be:

 ext/xmlrpc/libxmlrpc/xml_element.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/ext/xmlrpc/libxmlrpc/xml_element.c b/ext/xmlrpc/libxmlrpc/xml_element.c
index 070680d4a7..d2c7b5b78d 100644
--- a/ext/xmlrpc/libxmlrpc/xml_element.c
+++ b/ext/xmlrpc/libxmlrpc/xml_element.c
@@ -720,6 +720,9 @@ xml_element* xml_elem_parse_buf(const char* in_buf, int len, XML_ELEM_INPUT_OPTI
          long byte_idx = XML_GetCurrentByteIndex(parser);
 /*         int byte_total = XML_GetCurrentByteCount(parser); */
          const char * error_str = XML_ErrorString(err_code);
+         if(byte_idx > len) {
+            byte_idx = len;
+         }
          if(byte_idx >= 0) {
              snprintf(buf,
                       sizeof(buf),

[1] <https://github.com/php/php-src/blob/php-7.2.12/ext/xmlrpc/libxmlrpc/xml_element.c#L720>
[2] <http://git.php.net/?p=php-src.git;a=commit;h=780ff63c377dc79de2c04d6b341913ab0102135b>
[3] <https://sourceforge.net/projects/xmlrpc-epi/>
Links: https://bugs.php.net/bug.php?id=52998, https://github.com/php/php-src/blob/php-7.2.12/ext/xmlrpc/libxmlrpc/xml_element.c#L720, http://git.php.net/?p=php-src.git;a=commit;h=780ff63c377dc79de2c04d6b341913ab0102135b, https://sourceforge.net/projects/xmlrpc-epi/

[Comment 2] [2018-12-16 01:19 UTC] stas@php.net
Yeah I wonder though what to do with this in more generic context... If libxml2 is insecure when passed non-sanitized input, then we should probably document all libraries using libxml2 as needing input sanitization before third-party external data can be passed to them? Specifically, I imagine, all of dom, libxml, simplexml, soap, wddx, xml, xmlreader, xmlrpc, xmlwriter could be affected?

[Comment 3] [2018-12-30 02:01 UTC] stas@php.net
In security repo as b9d761168318d91be38dc25b51714eedf2dea045

[Comment 4] [2018-12-30 02:33 UTC] stas@php.net
Related To: Bug #77249
Links: https://bugs.php.net/bug.php?id=77249

[Comment 5] [2018-12-30 08:50 UTC] hanno at hboeck dot de
Can you share the patch with me? I believe the security repo is probably non-public, so I can't access it.

[Comment 6] [2018-12-30 08:52 UTC] hanno at hboeck dot de
Related To: Bug #77249
Links: https://bugs.php.net/bug.php?id=77249

[Comment 8] [2019-01-07 08:14 UTC] stas@php.net
Related To: Bug #77249
Links: https://bugs.php.net/bug.php?id=77249

[Comment 18] [2019-01-09 11:58 UTC] cmb@php.net
Related To: Bug #77429
Links: https://bugs.php.net/bug.php?id=77429

[Comment 19] [2019-01-09 12:45 UTC] zhihua dot yao at dbappsecurity dot com dot cn
Related To: Bug #77429
Links: https://bugs.php.net/bug.php?id=77429

[Comment 20] [2019-02-10 12:06 UTC] cmb@php.net
Related To: Bug #77429
Links: https://bugs.php.net/bug.php?id=77429

Commit References:
b9d761168318d91be38dc25b51714eedf2dea045
780ff63c377dc79de2c04d6b341913ab0102135b

================= Bug Report (2/2) ==================
## Source: PHP Bugs
## URL: https://bugs.php.net/bug.php?id=77249
## Description:
PHP Bug ID: 77249
Summary: Use after free in xmlrpc_decode()
Status: Duplicate
PHP Version: 7.2.12
Assigned: stas (profile)

Description:
Description:
------------
Malformed input can lead to a use after free bug in xmlrpc_decode(). You need to use address sanitizer and USE_ZEND_ALLOC=0 to see the bug.

It seems also to depend on the input. If I pass it directly as a variable I get a buffer overread (already reported as bug #77242), yet if I pass it as a file or stdin I get the UAF. Use after free is potentially a more severe security vulnerability.

Test script:
---------------
Via command line and stdin:

echo 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iSVNPLTg4NTktNSI/PjxtPu+/vdTU1NTU1NTUaW54Png+77+91NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU79TU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NQ='|base64 -d | ./php -r '$a=xmlrpc_decode(file_get_contents("php://stdin"));'

Expected result:
----------------
No memory corruption.

Actual result:
--------------
Use after free:

==11008==ERROR: AddressSanitizer: heap-use-after-free on address 0x611000000e01 at pc 0x000000439739 bp 0x7ffcc2e3cbf0 sp 0x7ffcc2e3c398
READ of size 1 at 0x611000000e01 thread T0
    #0 0x439738 in __interceptor_strlen (/r/php/php+0x439738)
    #1 0x1614386 in format_converter /f/php/php-7.2.12/main/snprintf.c:997:15
    #2 0x1614386 in strx_printv /f/php/php-7.2.12/main/snprintf.c:1252
    #3 0x16104af in ap_php_snprintf /f/php/php-7.2.12/main/snprintf.c:1297:2
    #4 0x15e19ab in xml_elem_parse_buf /f/php/php-7.2.12/ext/xmlrpc/libxmlrpc/xml_element.c:724:14
    #5 0x15e3830 in XMLRPC_REQUEST_FromXML /f/php/php-7.2.12/ext/xmlrpc/libxmlrpc/xmlrpc.c:808:3
    #6 0x15c4f7b in decode_request_worker /f/php/php-7.2.12/ext/xmlrpc/xmlrpc-epi-php.c:763:13
    #7 0x15c4f7b in zif_xmlrpc_decode /f/php/php-7.2.12/ext/xmlrpc/xmlrpc-epi-php.c:818
    #8 0x1bc7c08 in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER /f/php/php-7.2.12/Zend/zend_vm_execute.h:617:2
    #9 0x1980f8c in execute_ex /f/php/php-7.2.12/Zend/zend_vm_execute.h:59739:7
    #10 0x1981875 in zend_execute /f/php/php-7.2.12/Zend/zend_vm_execute.h:63776:2
    #11 0x17be1d1 in zend_eval_stringl /f/php/php-7.2.12/Zend/zend_execute_API.c:1083:4
    #12 0x17beb0f in zend_eval_stringl_ex /f/php/php-7.2.12/Zend/zend_execute_API.c:1124:11
    #13 0x17beb0f in zend_eval_string_ex /f/php/php-7.2.12/Zend/zend_execute_API.c:1135
    #14 0x1d01706 in do_cli /f/php/php-7.2.12/sapi/cli/php_cli.c:1044:8
    #15 0x1cfee22 in main /f/php/php-7.2.12/sapi/cli/php_cli.c:1407:18
    #16 0x7f7c4c17f4ea in __libc_start_main (/lib64/libc.so.6+0x244ea)
    #17 0x423dc9 in _start (/r/php/php+0x423dc9)

0x611000000e01 is located 1 bytes inside of 256-byte region [0x611000000e00,0x611000000f00)
freed by thread T0 here:
    #0 0x4cdf32 in __interceptor_free (/r/php/php+0x4cdf32)
    #1 0x7f7c4e461432 in xmlCreatePushParserCtxt (/usr/lib64/libxml2.so.2+0x4a432)
    #2 0x15b5ca6 in php_XML_ParserCreate_MM /f/php/php-7.2.12/ext/xml/compat.c:465:19
    #3 0x15b5ca6 in php_XML_ParserCreate /f/php/php-7.2.12/ext/xml/compat.c:443
    #4 0x15e1672 in xml_elem_parse_buf /f/php/php-7.2.12/ext/xmlrpc/libxmlrpc/xml_element.c:698:16
    #5 0x15e3830 in XMLRPC_REQUEST_FromXML /f/php/php-7.2.12/ext/xmlrpc/libxmlrpc/xmlrpc.c:808:3
    #6 0x15c4f7b in decode_request_worker /f/php/php-7.2.12/ext/xmlrpc/xmlrpc-epi-php.c:763:13
    #7 0x15c4f7b in zif_xmlrpc_decode /f/php/php-7.2.12/ext/xmlrpc/xmlrpc-epi-php.c:818
    #8 0x1bc7c08 in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER /f/php/php-7.2.12/Zend/zend_vm_execute.h:617:2
    #9 0x1980f8c in execute_ex /f/php/php-7.2.12/Zend/zend_vm_execute.h:59739:7
    #10 0x1981875 in zend_execute /f/php/php-7.2.12/Zend/zend_vm_execute.h:63776:2
    #11 0x17be1d1 in zend_eval_stringl /f/php/php-7.2.12/Zend/zend_execute_API.c:1083:4
    #12 0x17beb0f in zend_eval_stringl_ex /f/php/php-7.2.12/Zend/zend_execute_API.c:1124:11
    #13 0x17beb0f in zend_eval_string_ex /f/php/php-7.2.12/Zend/zend_execute_API.c:1135
    #14 0x1d01706 in do_cli /f/php/php-7.2.12/sapi/cli/php_cli.c:1044:8
    #15 0x1cfee22 in main /f/php/php-7.2.12/sapi/cli/php_cli.c:1407:18
    #16 0x7f7c4c17f4ea in __libc_start_main (/lib64/libc.so.6+0x244ea)
    #17 0x423dc9 in _start (/r/php/php+0x423dc9)

previously allocated by thread T0 here:
    #0 0x4ce2b3 in __interceptor_malloc (/r/php/php+0x4ce2b3)
    #1 0x7f7c4e44f32d in xmlInitParserCtxt (/usr/lib64/libxml2.so.2+0x3832d)
    #2 0x7f7c4e44f59d in xmlNewParserCtxt (/usr/lib64/libxml2.so.2+0x3859d)
    #3 0x7f7c4e4613ca in xmlCreatePushParserCtxt (/usr/lib64/libxml2.so.2+0x4a3ca)
    #4 0x15b5ca6 in php_XML_ParserCreate_MM /f/php/php-7.2.12/ext/xml/compat.c:465:19
    #5 0x15b5ca6 in php_XML_ParserCreate /f/php/php-7.2.12/ext/xml/compat.c:443
    #6 0x15e1672 in xml_elem_parse_buf /f/php/php-7.2.12/ext/xmlrpc/libxmlrpc/xml_element.c:698:16
    #7 0x15e3830 in XMLRPC_REQUEST_FromXML /f/php/php-7.2.12/ext/xmlrpc/libxmlrpc/xmlrpc.c:808:3
    #8 0x15c4f7b in decode_request_worker /f/php/php-7.2.12/ext/xmlrpc/xmlrpc-epi-php.c:763:13
    #9 0x15c4f7b in zif_xmlrpc_decode /f/php/php-7.2.12/ext/xmlrpc/xmlrpc-epi-php.c:818
    #10 0x1bc7c08 in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER /f/php/php-7.2.12/Zend/zend_vm_execute.h:617:2
    #11 0x1980f8c in execute_ex /f/php/php-7.2.12/Zend/zend_vm_execute.h:59739:7
    #12 0x1981875 in zend_execute /f/php/php-7.2.12/Zend/zend_vm_execute.h:63776:2
    #13 0x17be1d1 in zend_eval_stringl /f/php/php-7.2.12/Zend/zend_execute_API.c:1083:4
    #14 0x17beb0f in zend_eval_stringl_ex /f/php/php-7.2.12/Zend/zend_execute_API.c:1124:11
    #15 0x17beb0f in zend_eval_string_ex /f/php/php-7.2.12/Zend/zend_execute_API.c:1135
    #16 0x1d01706 in do_cli /f/php/php-7.2.12/sapi/cli/php_cli.c:1044:8
    #17 0x1cfee22 in main /f/php/php-7.2.12/sapi/cli/php_cli.c:1407:18
    #18 0x7f7c4c17f4ea in __libc_start_main (/lib64/libc.so.6+0x244ea)
    #19 0x423dc9 in _start (/r/php/php+0x423dc9)

Comments:

[Comment 1] [2018-12-30 02:33 UTC] stas@php.net
Looks like the fix for bug #77242 fixes this one too.
Links: https://bugs.php.net/bug.php?id=77242

[Comment 2] [2018-12-30 02:33 UTC] stas@php.net
Also backtrace seems to point to the same place, so it is plausible.

[Comment 3] [2018-12-30 08:52 UTC] hanno at hboeck dot de
Likely the same bug, but relevant to point out that this is use after free, which may be more severe than a pure overread that I reported in bug #77242
Links: https://bugs.php.net/bug.php?id=77242

[Comment 4] [2019-01-07 08:14 UTC] stas@php.net
See bug #77242
Links: https://bugs.php.net/bug.php?id=77242

[Comment 5] [2022-06-07 03:12 UTC] 1030255014 at qq dot com
The following pull request has been associated:

Patch Name: PHP-FPM 中译文更新
On GitHub:  https://github.com/php/doc-zh/pull/243
Patch:      https://github.com/php/doc-zh/pull/243.patch
Links: https://github.com/php/doc-zh/pull/243, https://github.com/php/doc-zh/pull/243.patch

Build script:
#!/bin/bash -eu
# Minimized build script with only core build commands
set -eu
./buildconf --force
./configure \
        --enable-option-checking=fatal \
        --disable-libxml \
        --disable-dom \
        --disable-simplexml \
        --disable-xml \
        --disable-xmlreader \
        --disable-xmlwriter \
        --without-pear \
        --enable-exif \
        --disable-phpdbg \
        --disable-cgi
make -j$(nproc)

Dockerfile:
FROM hwiwonlee/secb.base:latest
RUN apt-get update && apt-get install -y make autoconf automake libtool bison re2c make ca-certificates curl xz-utils dpkg-dev file libc-dev pkg-config libcurl4-openssl-dev libedit-dev libsqlite3-dev libssl-dev zlib1g-dev
RUN git clone https://github.com/php/php-src php-src
RUN git -C php-src checkout 05fb10165081cb4fb55a9943b44cab62c627db7a
WORKDIR $SRC/php-src
COPY build.sh $SRC/

Additional files: